home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 June / EnigmA AMIGA RUN 08 (1996)(G.R. Edizioni)(IT)[!][issue 1996-06][EARSAN CD VII].iso / earcd / comm1 / s342q12.lha / cit_zmodem.c < prev    next >
C/C++ Source or Header  |  1995-09-16  |  106KB  |  4,019 lines

  1. #include <exec/types.h>
  2. #include <dos/dos.h>
  3. #include <devices/timer.h>
  4. #include <clib/exec_protos.h>
  5. #include <exec/memory.h>
  6. #include <ctype.h>
  7. #include <time.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <exec/execbase.h>
  12. #include <math.h>
  13. #include <devices/timer.h>
  14. #include <devices/serial.h>
  15. #include "xproto.h"
  16. #include <exec/memory.h>
  17. #include "ctdl.h"
  18. #include "sysdep.h"
  19. #include "xproto.h"
  20. #include "zmodem.h"
  21. #include "xprzmodem.h"
  22.  
  23. struct Library *TimerBase;
  24. static struct XPR_IO xio;
  25. static struct timerequest treq;
  26. static struct MsgPort *tport;
  27. static char timeropen;
  28.  
  29. extern CONFIG    cfg;            /* Lots an lots of variables    */
  30.  
  31. extern struct IOExtSer *mySerReadMsg;
  32. extern struct MsgPort *mySerReadPort;
  33. struct IOExtSer *xpr_serio;
  34. struct MsgPort *smp;
  35.  
  36. long xpr_sread(char *buffer, long size, long timeout);
  37. long xpr_swrite(char *buffer, long size);
  38. long xpr_sflush(void);
  39. long xpr_ffirst(char *buffer, char *pattern);
  40. long xpr_fnext(long OldState, char *buffer, char *pattern);
  41. long xpr_finfo(char *name, long type);
  42. long xpr_gets(char *b, char *p);
  43.  
  44.  
  45. long xpr_chkabort(void);
  46. void init_xpr ( struct XPR_IO *IO );
  47. void plog(char *string, long arg1, long arg2  );
  48.  
  49.  
  50. long   display_update (struct XPR_UPDATE *xu );
  51. long   Do_Zmodem(char *filename, int sending);
  52.  
  53. void close_xpr ( void );
  54.  
  55. char *filelist;   /* initial file list from Citadel */
  56.  
  57. long
  58. Do_Zmodem(filename, sending)
  59. char   *filename;            /* file(s) to  send/recieve  */
  60. int     sending;             /* TRUE - sending, FALSE - receive */
  61.   {
  62.   long status;
  63.   plog("Files:%s Direction:%s",(long)filename, (long)(sending ? "TRUE" : "FALSE") );
  64.   xpr_serio = mySerReadMsg;
  65.   smp       = mySerReadPort;
  66.   init_xpr(&xio);
  67.   status = TRUE;
  68.   if (!xpr_chkabort())
  69.     {
  70.     filelist         = filename;
  71.     xio.xpr_filename = strtok(filelist," ");  /* Citadel delimits with a space*/
  72.     if (!sending)
  73.       {
  74.       status = XProtocolSend(&xio);
  75.       plog("XProtocolSend returned: %08.8lX",status,0L);
  76.       }
  77.     else
  78.       {
  79.       status = XProtocolReceive(&xio);
  80.       plog("XProtocolReceive returned: %08.8lX",status,0L);
  81.       };
  82.     };
  83.   XProtocolCleanup(&xio);
  84.   return  status;
  85.   }
  86. void
  87. init_xpr(struct XPR_IO *IO)
  88.   {
  89.   plog("init_xpr: XPR_IO =%08.8lX", (long)IO, 0L);
  90.   IO->xpr_filename  = NULL;
  91.   IO->xpr_data      = NULL;
  92.   }
  93.  
  94. void
  95. plog(char *string, long arg1, long arg2)
  96.   {
  97.   long    t;
  98.     t = time(0);
  99.     splitF(NULL,"%24.24s : ", ctime(&t));
  100.     splitF(NULL, string, arg1, arg2);
  101.     splitF(NULL, "\n", 1);
  102.  
  103.   }
  104.  
  105. char the_protocol[20];  /* the current protocol name */
  106. char the_file[30];      /* the current filename */
  107. long the_size;          /* size of current file */
  108.  
  109. long   display_update (struct XPR_UPDATE *xu )
  110.   {
  111.   int flag = FALSE;
  112.   if( !xu)
  113.     {
  114.     plog(" XPR_UPDATE is NULL",0L, 0L);
  115.     return 0;
  116.     }
  117.   if( XPRU_PROTOCOL && xu->xpru_updatemask)
  118.     {
  119.     if( xu->xpru_protocol)strncpy(the_protocol,xu->xpru_protocol,19);
  120.     the_protocol[19] = '\0';
  121.     };
  122.   if( XPRU_FILENAME && xu->xpru_updatemask)
  123.     {
  124.     if( xu->xpru_filename)strncpy(the_file,xu->xpru_filename,29);
  125.     the_protocol[19] = '\0';
  126.     flag = TRUE;
  127.     };
  128.   if( XPRU_FILESIZE && xu->xpru_updatemask)the_size = xu->xpru_filesize;
  129.   if( XPRU_MSG && xu->xpru_updatemask)
  130.     plog("XPRU_MSG:%s",(long)xu->xpru_msg,0L);
  131.   if( XPRU_ERRORMSG && xu->xpru_updatemask)
  132.     plog("XPRU_ERRORMSG:%s on file %s",(long)xu->xpru_errormsg,(long)the_file);
  133.   if( XPRU_ERRORS && xu->xpru_updatemask)
  134.     {
  135.     if( xu->xpru_errors != 0 )
  136.       plog("XPRU_ERRORS:%ld on file %s",(long)xu->xpru_errors,(long)the_file);
  137.     };
  138.   if( flag )
  139.     {
  140.     plog("Protocol:%s File:%s",(long)the_protocol,(long)the_file);
  141.     };
  142.   return 1;
  143.   }
  144.  
  145. long    xpr_chkabort(void)
  146.   {
  147.   return (gotCarrier()? 0L : -1L);
  148.  
  149.   }
  150. long  opentimer(void)
  151.   {
  152.   plog("opentimer", 0L, 0L);
  153.   tport = CreatePort(0, 0);
  154.   if (!tport)  return (-1);
  155.   treq.tr_node.io_Message.mn_ReplyPort = tport;
  156.   if (OpenDevice("timer.device", UNIT_VBLANK, (struct IORequest *) &treq, 0))
  157.   return (-1);
  158.   TimerBase = (struct Library *)treq.tr_node.io_Device;
  159.   timeropen = 1;
  160.   return (0);
  161.  
  162.   }
  163. void  closetimer(void)
  164.   {
  165.   plog("closetimer", 0L, 0L);
  166.   if (timeropen)
  167.   CloseDevice((struct IORequest *) &treq);
  168.   if (tport)
  169.   DeletePort(tport);
  170.   TimerBase = NULL;
  171.   }
  172. void  qtimer(long micros)
  173.   {
  174.   long    secs = 0;
  175.   plog("qtimer: micros = %ld", micros, 0L);
  176.   if (micros > 1000000)
  177.     {
  178.     secs = micros / 1000000;
  179.     micros = micros % 1000000;
  180.  
  181.     }
  182.   treq.tr_time.tv_micro = micros;
  183.   treq.tr_time.tv_secs = secs;
  184.   treq.tr_node.io_Command = TR_ADDREQUEST;
  185.   /* printf("QTIMER  * s=%ld  * m=%ld\n",secs,micros); */
  186.   SendIO((struct IORequest *) &treq);
  187.  
  188.   }
  189. /* the * finfo-function  */
  190. long
  191. xpr_finfo(char * FileName,LONG InfoType)
  192.   {
  193.   struct FileInfoBlock    *FileInfo;
  194.   LONG                     Size=0;
  195.   plog("finfo:%s, InfoType:%ld", 0L, 0L);
  196.   switch(InfoType)
  197.     {
  198.     case 1:       /* Return the file size. */
  199.       if(FileInfo = (struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock), MEMF_CLEAR))
  200.         {
  201.         BPTR    FileLock;
  202.         if(FileLock = Lock(FileName,ACCESS_READ))
  203.           {
  204.           if(Examine(FileLock,FileInfo))
  205.             {
  206.             if(FileInfo -> fib_DirEntryType < 0)Size = FileInfo->fib_Size;
  207.             };
  208.           UnLock(FileLock);
  209.           };
  210.         FreeMem(FileInfo, sizeof(struct FileInfoBlock));
  211.         };
  212.       break;
  213.     case 2:         /* Return the file transfer mode. */
  214.       Size = 1; /* always return Binary */
  215.     break;
  216.    }
  217. return Size;
  218. }
  219.  
  220.  
  221. /* the * serwrite  * function  */
  222. long
  223. xpr_swrite(char *buffer, long size)
  224.   {
  225.   plog("swrite:%08.8lX of size %ld", (long)buffer, size);
  226.   xpr_serio->IOSer.io_Length  = size;
  227.   xpr_serio->IOSer.io_Data    = buffer;
  228.   xpr_serio->IOSer.io_Command = CMD_WRITE;
  229.   DoIO((struct IORequest *) xpr_serio);
  230.   if( xpr_serio->IOSer.io_Error )
  231.     plog("  Error:%08.8lx", xpr_serio->IOSer.io_Error, 0L);
  232.   return ((long) xpr_serio->IOSer.io_Error);
  233.  
  234.   }
  235. /* the * serread  * function  */
  236. long
  237. xpr_sread(char *buffer, long size, long timeout)
  238.   {
  239.   long    flag = 1 << xpr_serio->IOSer.io_Message.mn_ReplyPort->mp_SigBit;
  240.   long    len,
  241.   nflag;
  242.   plog("sread: size %ld with timeout of %ld", size, timeout);
  243.   SetSignal(0, flag);
  244.   if (timeout)
  245.     {
  246.     flag |= 1 << tport->mp_SigBit;
  247.     /* printf("Starting  * timer...\n"); */
  248.     qtimer(timeout);
  249.  
  250.     }
  251.   else
  252.     {
  253.     xpr_serio->IOSer.io_Command = SDCMD_QUERY;
  254.     DoIO((struct IORequest *) xpr_serio);
  255.     if (!(len = xpr_serio->IOSer.io_Actual))
  256.     return (0);
  257.     else
  258.       {
  259.       if (len > size)
  260.       len = size;
  261.       xpr_serio->IOSer.io_Command = CMD_READ;
  262.       xpr_serio->IOSer.io_Data = buffer;
  263.       xpr_serio->IOSer.io_Length = len;
  264.       DoIO((struct IORequest *) xpr_serio);
  265.       /* printf("Fastread  * return  * * * *
  266.       * %ld\n",xpr_serio->IOSer.io_Actual); */
  267.       return ((long) xpr_serio->IOSer.io_Actual);
  268.  
  269.       }
  270.  
  271.     }
  272.   SetSignal(0, flag);
  273.   xpr_serio->IOSer.io_Command = CMD_READ;
  274.   xpr_serio->IOSer.io_Data = buffer;
  275.   xpr_serio->IOSer.io_Length = size;
  276.   SendIO((struct IORequest *) xpr_serio);
  277.   nflag = Wait(flag);
  278.   if (nflag)
  279.     {
  280.     AbortIO((struct IORequest *) &treq);
  281.     AbortIO((struct IORequest *) xpr_serio);
  282.     WaitIO((struct IORequest *) &treq);
  283.     WaitIO((struct IORequest *) xpr_serio);
  284.     return (-1);
  285.  
  286.     }
  287.   if (nflag & (1 << xpr_serio->IOSer.io_Message.mn_ReplyPort->mp_SigBit))
  288.     {
  289.     AbortIO((struct IORequest *) &treq);
  290.     WaitIO((struct IORequest *) xpr_serio);
  291.     WaitIO((struct IORequest *) &treq);
  292.     return ((long) xpr_serio->IOSer.io_Actual);
  293.  
  294.     }
  295.   plog("  Timeout occured", 0L, 0L);
  296.   AbortIO((struct IORequest *) xpr_serio);
  297.   WaitIO((struct IORequest *) &treq);
  298.   WaitIO((struct IORequest *) xpr_serio);
  299.   return ((long) xpr_serio->IOSer.io_Actual);
  300.  
  301.   }
  302. /* sflush  * - * flushes  * serial  * port  */
  303. long
  304. xpr_sflush(void)
  305.   {
  306.   plog("sflush", 0L, 0L);
  307.   xpr_serio->IOSer.io_Command = CMD_CLEAR;
  308.   DoIO((struct IORequest *) xpr_serio);
  309.   if( xpr_serio->IOSer.io_Error )
  310.     plog("  Error:%08.8lx", xpr_serio->IOSer.io_Error, 0L);
  311.   return ((long) xpr_serio->IOSer.io_Error);
  312.  
  313.   }
  314. /**
  315.   ffirst() -- setup first filename and return it
  316. **/
  317. long
  318. xpr_ffirst(char *buffer, char *pattern)
  319.   {
  320.   char *token;
  321.   plog("ffirst",0L,0L);
  322.   token = strtok(NULL," ");  /* Citadel delimits filenames with a space*/
  323.   if( token != NULL )
  324.     {
  325.     plog("  filename:%s", (long)token, 0L);
  326.     strcpy(buffer,token);
  327.     return(1);
  328.     }
  329.   return (0);
  330.   }
  331.  
  332. long
  333. xpr_fnext(long OldState,
  334.           char *buffer,
  335.           char *pattern)
  336.   {
  337.   char *token;
  338.   plog("fnext",0L,0L);
  339.   token = strtok(NULL," ");  /* Citadel delimits filenames with a space*/
  340.   if( token != NULL )
  341.     {
  342.     plog("  filename:%s", (long)token, 0L);
  343.     strcpy(buffer,token);
  344.     return(1);
  345.     }
  346.   return (0);
  347.   }
  348.  
  349.  
  350. void
  351. close_xpr(void)
  352.   {
  353.   plog("close_xpr",0L, 0L);
  354.   closetimer();
  355.  
  356.   }
  357. /**********************************************************************
  358.  *   Z M . C
  359.  *    ZMODEM protocol primitives
  360.  *    01-19-87  Chuck Forsberg Omen Technology Inc
  361.  *
  362.  * 05-Apr-95: Converted to become a part of Citadel
  363.  *
  364.  * 29 July 89:
  365.  * Major overhaul by Rick Huebner for adaptation to Amiga XPR protocol spec
  366.  *
  367.  * 28 October 89:
  368.  * Converted to Lattice C 5.04
  369.  *
  370.  * 15 November 1991
  371.  * Code added to support CRC-32 by William M. Perkins.
  372.  *
  373.  * 28 June 1993
  374.  * Added run-length encoding code from original ZModem sources.
  375.  **********************************************************************/
  376.  
  377. /*
  378.  * Fast table-driven CRC functions for ZMODEM
  379.  * * extracted from RBSB.C by Chuck Forsberg, Omen Technology, Inc.
  380.  * *
  381.  * * crctab calculated by Mark G. Mendel, Network Systems Corporation
  382.  */
  383.  
  384. static unsigned short crctab[256] =
  385. {
  386.   0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
  387.   0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
  388.   0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
  389.   0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
  390.   0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
  391.   0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
  392.   0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
  393.   0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
  394.   0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
  395.   0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
  396.   0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
  397.   0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
  398.   0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
  399.   0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
  400.   0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
  401.   0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
  402.   0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
  403.   0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
  404.   0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
  405.   0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
  406.   0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
  407.   0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
  408.   0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
  409.   0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
  410.   0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
  411.   0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
  412.   0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
  413.   0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
  414.   0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
  415.   0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
  416.   0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
  417.   0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
  418. };
  419.  
  420. /*
  421.  * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell.
  422.  *  NOTE: First srgument must be in range 0 to 255.
  423.  *        Second argument is referenced twice.
  424.  *
  425.  * Programmers may incorporate any or all code into their programs,
  426.  * giving proper credit within the source. Publication of the
  427.  * source routines is permitted so long as proper credit is given
  428.  * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg,
  429.  * Omen Technology.
  430.  */
  431.  
  432. #define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)
  433.  
  434. /*
  435.  * Copyright (C) 1986 Gary S. Brown.  You may use this program, or
  436.  * code or tables extracted from it, as desired without restriction.
  437.  */
  438.  
  439. /*
  440.  * First, the polynomial itself and its table of feedback terms.  The
  441.  * polynomial is
  442.  * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
  443.  * Note that we take it "backwards" and put the highest-order term in
  444.  * the lowest-order bit.  The X^32 term is "implied"; the LSB is the
  445.  * X^31 term, etc.  The X^0 term (usually shown as "+1") results in
  446.  * the MSB being 1.
  447.  *
  448.  * Note that the usual hardware shift  implementation, which
  449.  * is what we're using (we're merely optimizing it by doing eight-bit
  450.  * chunks at a time) shifts bits into the lowest-order term.  In our
  451.  * implementation, that means shifting towards the right.  Why do we
  452.  * do it this way?  Because the calculated CRC must be transmitted in
  453.  * order from highest-order term to lowest-order term.  UARTs transmit
  454.  * characters in order from LSB to MSB.  By storing the CRC this way,
  455.  * we hand it to the UART in the order low-byte to high-byte; the UART
  456.  * sends each low-bit to hight-bit; and the result is transmission bit
  457.  * by bit from highest- to lowest-order term without requiring any bit
  458.  * shuffling on our part.  Reception works similarly.
  459.  */
  460.  
  461. /*
  462.  * The feedback terms table consists of 256, 32-bit entries.  Notes:
  463.  *
  464.  *     The table can be generated at runtime if desired; code to do so
  465.  *     is shown later.  It might not be obvious, but the feedback
  466.  *     terms simply represent the results of eight shift/xor opera-
  467.  *     tions for all combinations of data and CRC  values.
  468.  *
  469.  *     The values must be right-shifted by eight bits by the "updcrc"
  470.  *     logic; the shift must be unsigned (bring in zeroes).  On some
  471.  *     hardware you could probably optimize the shift in assembler by
  472.  *     using byte-swap instructions.
  473.  */
  474.  
  475. static unsigned long cr3tab[] =   /*
  476.                                    * CRC polynomial 0xedb88320
  477.                                    */
  478. {
  479.   0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
  480.   0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
  481.   0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
  482.   0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
  483.   0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
  484.   0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
  485.   0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
  486.   0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
  487.   0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
  488.   0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
  489.   0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
  490.   0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
  491.   0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
  492.   0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
  493.   0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
  494.   0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
  495.   0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
  496.   0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
  497.   0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
  498.   0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
  499.   0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
  500.   0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
  501.   0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
  502.   0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
  503.   0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
  504.   0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
  505.   0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
  506.   0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
  507.   0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
  508.   0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
  509.   0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
  510.   0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
  511.   0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
  512.   0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
  513.   0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
  514.   0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
  515.   0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
  516.   0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
  517.   0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
  518.   0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
  519.   0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
  520.   0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
  521.   0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
  522. };
  523.  
  524. #define UPDC32(b, c) (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF))
  525.  
  526. static char *frametypes[] =
  527. {
  528.   "CARRIER_LOST",                 /*
  529.                                    * -3
  530.                                    */
  531.   "TIMEOUT",                      /*
  532.                                    * -2
  533.                                    */
  534.   "ERROR",                        /*
  535.                                    * -1
  536.                                    */
  537. #define FTOFFSET 3
  538.   "ZRQINIT",
  539.   "ZRINIT",
  540.   "ZSINIT",
  541.   "ZACK",
  542.   "ZFILE",
  543.   "ZSKIP",
  544.   "ZNAK",
  545.   "ZABORT",
  546.   "ZFIN",
  547.   "ZRPOS",
  548.   "ZDATA",
  549.   "ZEOF",
  550.   "ZFERR",
  551.   "ZCRC",
  552.   "ZCHALLENGE",
  553.   "ZCOMPL",
  554.   "ZCAN",
  555.   "ZFREECNT",
  556.   "ZCOMMAND",
  557.   "ZSTDERR",
  558.   "xxxxx"
  559. #define FRTYPES 22                /*
  560.                                    * Total number of frame types in this
  561.                                    * array
  562.                                    */
  563.                         /*
  564.                          * not including psuedo negative entries
  565.                          */
  566. };
  567.  
  568. /**********************************************************
  569.  *      void zsbhdr(struct Vars *v, USHORT type)
  570.  *
  571.  * Send ZMODEM binary header hdr of type type
  572.  **********************************************************/
  573. void
  574. zsbhdr(struct Vars *v, USHORT type)
  575. {
  576.   UBYTE    *hdr = v->Txhdr;
  577.   short     n;
  578.   USHORT    crc;
  579.   ULONG     crc32;
  580.  
  581.   xsendline(v, ZPAD);
  582.   xsendline(v, ZDLE);
  583.  
  584.   if (v->Crc32t = v->Txfcs32)   /*
  585.                                  * zsbh32()
  586.                                  */
  587.     {
  588.       xsendline(v, ZBIN32);
  589.       zsendline(v, (UBYTE) type);
  590.  
  591.       crc32 = 0xFFFFFFFFL;
  592.       crc32 = UPDC32(type, crc32);
  593.  
  594.       for (n = 4; --n >= 0; ++hdr)
  595.         {
  596.           crc32 = UPDC32((0377 & *hdr), crc32);
  597.           zsendline(v, *hdr);
  598.         }
  599.       crc32 = ~crc32;
  600.       for (n = 4; --n >= 0;)
  601.         {
  602.           zsendline(v, (int) crc32);
  603.           crc32 >>= 8;
  604.         }
  605.     }
  606.   else
  607.     {
  608.       xsendline(v, ZBIN);
  609.       zsendline(v, (UBYTE) type);
  610.  
  611.       crc = updcrc(type, 0);
  612.       for (n = 4; --n >= 0;)
  613.         {
  614.           zsendline(v, *hdr);
  615.           crc = updcrc(((USHORT) (*hdr++)), crc);
  616.         }
  617.  
  618.       crc = updcrc(((USHORT) 0), crc);
  619.       crc = updcrc(((USHORT) 0), crc);
  620.       zsendline(v, (UBYTE) (crc >> 8));
  621.       zsendline(v, (UBYTE) crc);
  622.     }
  623. }       /*
  624.          * End of void zsbhdr()
  625.          */
  626.  
  627. /**********************************************************
  628.  *      void zshhdr(struct Vars *v, USHORT type)
  629.  *
  630.  * Send ZMODEM HEX header hdr of type type
  631.  **********************************************************/
  632. void
  633. zshhdr(struct Vars *v, USHORT type)
  634. {
  635.   UBYTE    *hdr = v->Txhdr;
  636.   short     n;
  637.   USHORT    crc;
  638.  
  639.   sendline(v, ZPAD);
  640.   sendline(v, ZPAD);
  641.   sendline(v, ZDLE);
  642.   sendline(v, ZHEX);
  643.   zputhex(v, (UBYTE) type);
  644.   v->Crc32t = 0;
  645.  
  646.   crc = updcrc(type, 0);
  647.   for (n = 4; --n >= 0;)
  648.     {
  649.       zputhex(v, *hdr);
  650.       crc = updcrc(((USHORT) (*hdr++)), crc);
  651.     }
  652.  
  653.   crc = updcrc(((USHORT) 0), crc);
  654.   crc = updcrc(((USHORT) 0), crc);
  655.   zputhex(v, (UBYTE) (crc >> 8));
  656.   zputhex(v, (UBYTE) crc);
  657.  
  658. /*
  659.  * Make it printable on remote machine
  660.  */
  661.   sendline(v, '\r');
  662.   sendline(v, '\n');
  663. /*
  664.  * Uncork the remote in case a fake XOFF has stopped data flow
  665.  */
  666.   if (type != ZFIN)
  667.     sendline(v, ZM_XON);
  668. }       /*
  669.          * End of void zshhdr()
  670.          */
  671.  
  672. /**********************************************************
  673.  *      void zsdata() and void zsda32()
  674.  *
  675.  * Send binary array buf of length length, with ending
  676.  * ZDLE sequence frameend
  677.  **********************************************************/
  678.  
  679. void
  680. zsdata(struct Vars *v, short length, USHORT frameend)
  681. {
  682.   UBYTE    *buf;
  683.  
  684.   buf = v->Pktbuf;
  685.  
  686.   if (v->Crc32t)
  687.     {
  688.       short     c;
  689.       ULONG     crc;
  690.  
  691.       crc = 0xFFFFFFFFL;
  692.       for (; --length >= 0; ++buf)
  693.         {
  694.           c = *buf;
  695.           if (c & 0140)
  696.             xsendline(v, v->Lastzsent = c);
  697.           else
  698.             zsendline(v, c);
  699.           crc = UPDC32(c, crc);
  700.         }
  701.       xsendline(v, ZDLE);
  702.       xsendline(v, frameend);
  703.       crc = UPDC32(frameend, crc);
  704.  
  705.       crc = ~crc;
  706.       for (c = 4; --c >= 0;)
  707.         {
  708.           zsendline(v, (int) crc);
  709.           crc >>= 8;
  710.         }
  711.     }
  712.   else
  713.     {
  714.       unsigned short crc;
  715.  
  716.       crc = 0;
  717.       for (; --length >= 0; ++buf)
  718.         {
  719.           zsendline(v, *buf);
  720.           crc = updcrc(*buf, crc);
  721.         }
  722.       xsendline(v, ZDLE);
  723.       xsendline(v, frameend);
  724.       crc = updcrc(frameend, crc);
  725.  
  726.       crc = updcrc(0, updcrc(0, crc));
  727.       zsendline(v, crc >> 8);
  728.       zsendline(v, crc);
  729.     }
  730.   if (frameend == ZCRCW)
  731.     {
  732.       xsendline(v, ZM_XON);
  733.     }
  734. }       /*
  735.          * End of void zsdata()
  736.          */
  737.  
  738. /**********************************************************
  739.  *      short zrdata(struct Vars *v, UBYTE *buf, short length)
  740.  *
  741.  * Receive array buf of max length with ending ZDLE sequence
  742.  * and CRC-16.  Returns the ending character or error code.
  743.  **********************************************************/
  744. short
  745. zrdata(struct Vars *v, UBYTE *buf, short length)
  746. {
  747.   short     c,
  748.             d;
  749.   USHORT    crc;
  750.  
  751.   if (v->Rxframeind == ZBIN32)
  752.     return zrdat32(v, buf, length);
  753.  
  754.   crc = v->Rxcount = 0;
  755.   for (;;)
  756.     {
  757.       if ((c = zdlread(v)) & ~0xFF)
  758.         {
  759.         crcfoo:
  760.           switch (c)
  761.             {
  762.               case GOTCRCE:
  763.               case GOTCRCG:
  764.               case GOTCRCQ:
  765.               case GOTCRCW:
  766.                 crc = updcrc(((d = c) & 0xFF), crc);
  767.                 if ((c = zdlread(v)) & ~0xFF)
  768.                   goto crcfoo;
  769.                 crc = updcrc(c, crc);
  770.                 if ((c = zdlread(v)) & ~0xFF)
  771.                   goto crcfoo;
  772.                 crc = updcrc(c, crc);
  773.                 if (crc & 0xFFFF)
  774.                   {
  775.                     strcpy(v->Msgbuf, "MSG_BAD_DATA_CRC16");
  776.                     return ZM_ERROR;
  777.                   }
  778.                 return d;
  779.               case GOTCAN:
  780.                 strcpy(v->Msgbuf, "MSG_SENDER_CANCELED");
  781.                 return ZCAN;
  782.               case TIMEOUT:
  783.                 strcpy(v->Msgbuf, "MSG_DATA_PACKET_TIMEOUT_TXT");
  784.                 return c;
  785.               case RCDO:
  786.                 return c;
  787.               default:
  788.                 strcpy(v->Msgbuf, "MSG_UNRECOGNIZABLE_DATA_PACKET_TXT");
  789.                 return c;
  790.             }
  791.         }
  792.       if (--length < 0)
  793.         {
  794.           strcpy(v->Msgbuf, "MSG_DATA_PACKET_TOO_LONG_TXT");
  795.           return ZM_ERROR;
  796.         }
  797.       ++v->Rxcount;
  798.       *buf++ = c;
  799.       crc = updcrc(c, crc);
  800.       continue;
  801.     }
  802. }       /*
  803.          * End of short zrdata()
  804.          */
  805.  
  806. /**********************************************************
  807.  *      short zrdat32(struct Vars *v, UBYTE *buf, short length)
  808.  *
  809.  * Receive array buf of max length with ending ZDLE sequence
  810.  * and CRC-32.  Returns the ending character or error code.
  811.  **********************************************************/
  812. short
  813. zrdat32(struct Vars *v, UBYTE *buf, short length)
  814. {
  815.   short     c,
  816.             d;
  817.   ULONG     crc32;
  818.  
  819.   crc32 = 0xFFFFFFFFL;
  820.   v->Rxcount = 0;
  821.  
  822.   for (;;)
  823.     {
  824.       if ((c = zdlread(v)) & ~0xFF)
  825.         {
  826.         crcfoo:
  827.           switch (c)
  828.             {
  829.               case GOTCRCE:
  830.               case GOTCRCG:
  831.               case GOTCRCQ:
  832.               case GOTCRCW:
  833.                 d = c;
  834.                 c &= 0xFF;
  835.                 crc32 = UPDC32(c, crc32);
  836.                 if ((c = zdlread(v)) & ~0xFF)
  837.                   goto crcfoo;
  838.                 crc32 = UPDC32(c, crc32);
  839.                 if ((c = zdlread(v)) & ~0xFF)
  840.                   goto crcfoo;
  841.                 crc32 = UPDC32(c, crc32);
  842.                 if ((c = zdlread(v)) & ~0xFF)
  843.                   goto crcfoo;
  844.                 crc32 = UPDC32(c, crc32);
  845.                 if ((c = zdlread(v)) & ~0xFF)
  846.                   goto crcfoo;
  847.                 crc32 = UPDC32(c, crc32);
  848.                 if (crc32 != 0xDEBB20E3)
  849.                   {
  850.                     strcpy(v->Msgbuf, "MSG_BAD_DATA_CRC32_TXT");
  851.                     return ZM_ERROR;
  852.                   }
  853.                 return d;
  854.               case GOTCAN:
  855.                 strcpy(v->Msgbuf, "MSG_SENDER_CANCELED_TXT");
  856.                 return ZCAN;
  857.               case TIMEOUT:
  858.                 strcpy(v->Msgbuf, "MSG_DATA_PACKET_TIMEOUT_TXT");
  859.                 return c;
  860.               case RCDO:
  861.                 return c;
  862.               default:
  863.                 strcpy(v->Msgbuf, "MSG_UNRECOGNIZABLE_DATA_PACKET_TXT");
  864.                 return c;
  865.             }
  866.         }
  867.       if (--length < 0)
  868.         {
  869.           strcpy(v->Msgbuf, "MSG_DATA_PACKET_TOO_LONG_TXT");
  870.           return ZM_ERROR;
  871.         }
  872.       ++v->Rxcount;
  873.       *buf++ = c;
  874.       crc32 = UPDC32(c, crc32);
  875.       continue;
  876.     }
  877. }       /*
  878.          * End of short zrdat32()
  879.          */
  880.  
  881. /**********************************************************
  882.  *      short zgethdr(struct Vars *v)
  883.  *
  884.  * Read a ZMODEM header to hdr, either binary or hex.
  885.  *  On success return type of header.
  886.  *  Otherwise return negative on error.
  887.  **********************************************************/
  888. short
  889. zgethdr(struct Vars *v)
  890. {
  891.   short     c,
  892.             cancount;
  893.   long      n;
  894.  
  895.   n = v->Baud;  /*
  896.                  * Max characters before start of frame
  897.                  */
  898.   cancount = 5;
  899. again:
  900.   v->Rxframeind = v->Rxtype = 0;
  901.   switch (c = noxrd7(v))
  902.     {
  903.       case RCDO:
  904.       case TIMEOUT:
  905.         goto fifi;
  906.       case ZM_CAN:
  907.         if (--cancount <= 0)
  908.           {
  909.             c = ZCAN;
  910.             goto fifi;
  911.           }
  912.       case ZPAD:        /*
  913.                          * This is what we want.
  914.                          */
  915.         break;
  916.       default:
  917.       agn2:
  918.         if (--n <= 0)
  919.           {
  920.             strcpy(v->Msgbuf, "MSG_HEADER_SEARCH_GARBAGE_COUNT_EXCEEDED_TXT");
  921.             return ZM_ERROR;
  922.           }
  923.         if (c != ZM_CAN)
  924.           cancount = 5;
  925.         goto again;
  926.     }
  927.   cancount = 5;
  928. splat:
  929.   switch (c = noxrd7(v))
  930.     {
  931.       case ZPAD:
  932.         goto splat;
  933.       case RCDO:
  934.       case TIMEOUT:
  935.         goto fifi;
  936.       default:
  937.         goto agn2;
  938.       case ZDLE:        /*
  939.                          * This is what we want.
  940.                          */
  941.         break;
  942.     }
  943.  
  944.   switch (c = noxrd7(v))
  945.     {
  946.       case RCDO:
  947.       case TIMEOUT:
  948.         goto fifi;
  949.       case ZBIN:
  950.         v->Rxframeind = ZBIN;
  951.         v->Crc32 = FALSE;
  952.         c = zrbhdr(v);
  953.         break;
  954.       case ZBIN32:
  955.         v->Crc32 = v->Rxframeind = ZBIN32;
  956.         c = zrbhdr32(v);
  957.         break;
  958.       case ZHEX:
  959.         v->Rxframeind = ZHEX;
  960.         v->Crc32 = FALSE;
  961.         c = zrhhdr(v);
  962.         break;
  963.       case ZM_CAN:
  964.         if (--cancount <= 0)
  965.           {
  966.             c = ZCAN;
  967.             goto fifi;
  968.           }
  969.         goto agn2;
  970.       default:
  971.         goto agn2;
  972.     }
  973.   v->Rxpos = rclhdr(v);
  974. fifi:
  975.   switch (c)
  976.     {
  977.       case GOTCAN:
  978.         c = ZCAN;
  979.       case ZNAK:
  980.       case ZCAN:
  981.       case ZM_ERROR:
  982.       case TIMEOUT:
  983.       case RCDO:
  984.         sprintf(v->Msgbuf, "%s %s ", frametypes[c + FTOFFSET],
  985.                   (c >= 0) ? "MSG_HEADER" : "MSG_ERROR");
  986.     }
  987.   return c;
  988. }       /*
  989.          * End of short zgethdr()
  990.          */
  991.  
  992. /**********************************************************
  993.  *      short zrbhdr(struct Vars *v)
  994.  *
  995.  * Receive a binary style header (type and position)
  996.  **********************************************************/
  997. short
  998. zrbhdr(struct Vars *v)
  999. {
  1000.   UBYTE    *hdr = v->Rxhdr;
  1001.   short     c,
  1002.             n;
  1003.   USHORT    crc;
  1004.  
  1005.   if ((c = zdlread(v)) & ~0xFF)
  1006.     return c;
  1007.   v->Rxtype = c;
  1008.   crc = updcrc(c, 0);
  1009.  
  1010.   for (n = 4; --n >= 0;)
  1011.     {
  1012.       if ((c = zdlread(v)) & ~0xFF)
  1013.         return c;
  1014.       crc = updcrc(c, crc);
  1015.       *hdr++ = c;
  1016.     }
  1017.   if ((c = zdlread(v)) & ~0xFF)
  1018.     return c;
  1019.   crc = updcrc(c, crc);
  1020.   if ((c = zdlread(v)) & ~0xFF)
  1021.     return c;
  1022.   crc = updcrc(c, crc);
  1023.   if (crc & 0xFFFF)
  1024.     {
  1025.       strcpy(v->Msgbuf, "MSG_BAD_HEADER_CRC16_TXT");
  1026.       return ZM_ERROR;
  1027.     }
  1028.   return v->Rxtype;
  1029. }       /*
  1030.          * End of short zrbhdr()
  1031.          */
  1032.  
  1033. /**********************************************************
  1034.  *      short zrbhdr32(struct Vars *v)
  1035.  *
  1036.  * Receive a binary style header (type and position) with
  1037.  * 32 bit FCS
  1038.  **********************************************************/
  1039. short
  1040. zrbhdr32(struct Vars *v)
  1041. {
  1042.   UBYTE    *hdr = v->Rxhdr;
  1043.   short     c,
  1044.             n;
  1045.   ULONG     crc32;
  1046.  
  1047.   if ((c = zdlread(v)) & ~0xFF)
  1048.     return c;
  1049.   v->Rxtype = c;
  1050.   crc32 = 0xFFFFFFFFL;
  1051.   crc32 = UPDC32(c, crc32);
  1052.  
  1053.   for (n = 4; --n >= 0;)
  1054.     {
  1055.       if ((c = zdlread(v)) & ~0xFF)
  1056.         return c;
  1057.       crc32 = UPDC32(c, crc32);
  1058.       *hdr++ = c;
  1059.     }
  1060.   for (n = 4; --n >= 0;)
  1061.     {
  1062.       if ((c = zdlread(v)) & ~0xFF)
  1063.         return c;
  1064.       crc32 = UPDC32(c, crc32);
  1065.     }
  1066.   if (crc32 != 0xDEBB20E3)
  1067.     {
  1068.       strcpy(v->Msgbuf, "MSG_BAD_HEADER_CRC32_TXT");
  1069.       return ZM_ERROR;
  1070.     }
  1071.   return v->Rxtype;
  1072. }       /*
  1073.          * End of short zrbhdr32()
  1074.          */
  1075.  
  1076. /**********************************************************
  1077.  *      short zrhhdr(struct Vars *v)
  1078.  *
  1079.  * Receive a hex style header (type and position)
  1080.  **********************************************************/
  1081. short
  1082. zrhhdr(struct Vars *v)
  1083. {
  1084.   UBYTE    *hdr = v->Rxhdr;
  1085.   short     c,
  1086.             n;
  1087.   USHORT    crc;
  1088.  
  1089.   if ((c = zgethex(v)) < 0)
  1090.     return c;
  1091.   v->Rxtype = c;
  1092.   crc = updcrc(c, 0);
  1093.  
  1094.   for (n = 4; --n >= 0;)
  1095.     {
  1096.       if ((c = zgethex(v)) < 0)
  1097.         return c;
  1098.       crc = updcrc(c, crc);
  1099.       *hdr++ = c;
  1100.     }
  1101.   if ((c = zgethex(v)) < 0)
  1102.     return c;
  1103.   crc = updcrc(c, crc);
  1104.   if ((c = zgethex(v)) < 0)
  1105.     return c;
  1106.   crc = updcrc(c, crc);
  1107.   if (crc & 0xFFFF)
  1108.     {
  1109.       strcpy(v->Msgbuf, "MSG_BAD_HEADER_CRC_TXT");
  1110.       return ZM_ERROR;
  1111.     }
  1112.   if (readock(v, 1) == '\r')
  1113.     readock(v, 1);      /*
  1114.                          * Throw away possible cr/lf
  1115.                          */
  1116.   return v->Rxtype;
  1117. }       /*
  1118.          * End of short zrhhdr()
  1119.          */
  1120.  
  1121. /**********************************************************
  1122.  *      void zputhex(struct Vars *v, UBYTE c)
  1123.  *
  1124.  * Send a byte as two hex digits
  1125.  **********************************************************/
  1126. void
  1127. zputhex(struct Vars *v, UBYTE c)
  1128. {
  1129.   static char digits[] = "0123456789abcdef";
  1130.  
  1131.   sendline(v, digits[(c >> 4) & 0x0F]);
  1132.   sendline(v, digits[c & 0x0F]);
  1133. }       /*
  1134.          * End of void zputhex()
  1135.          */
  1136.  
  1137. /**********************************************************
  1138.  *      void zsendline(struct Vars *v, UBYTE c)
  1139.  *
  1140.  * Send character c with ZMODEM escape sequence encoding.
  1141.  * Escape ZDLE, real DLE, XON, XOFF, and CR following @ (Telenet net escape)
  1142.  **********************************************************/
  1143. void
  1144. zsendline(struct Vars *v, UBYTE c)
  1145. {
  1146.   static char actions[256] =
  1147.   {
  1148.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3,
  1149.     2, 2, 3, 2, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3,
  1150.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1151.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1152.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1153.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1154.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1155.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1156.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 3,
  1157.     2, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1158.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1159.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1160.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1161.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1162.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
  1163.     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
  1164.   };
  1165.  
  1166.   switch (actions[c])
  1167.     {
  1168.       case 0:
  1169.         xsendline(v, ZDLE);
  1170.         xsendline(v, v->Lastzsent = (c ^ 0100));
  1171.         break;
  1172.  
  1173.       case 1:
  1174.         if (!v->Zctlesc && (v->Lastzsent & 0177) != '@')
  1175.           goto sendit;
  1176.  
  1177.    /*
  1178.     * **** FALL THRU TO ****
  1179.     */
  1180.  
  1181.       case 2:
  1182.         xsendline(v, ZDLE);
  1183.         c ^= 0100;
  1184.  
  1185.       sendit:xsendline(v, v->Lastzsent = c);
  1186.         break;
  1187.  
  1188.       case 3:
  1189.         if (v->Zctlesc && !(c & 0140))
  1190.           {
  1191.             xsendline(v, ZDLE);
  1192.             c ^= 0100;
  1193.           }
  1194.  
  1195.         xsendline(v, v->Lastzsent = c);
  1196.         break;
  1197.     }
  1198. }       /*
  1199.          * End of void zsendline()
  1200.          */
  1201.  
  1202. /**********************************************************
  1203.  *      short zgethex(struct Vars *v)
  1204.  *
  1205.  * Decode two lower case hex digits into an 8 bit byte value
  1206.  **********************************************************/
  1207. short
  1208. zgethex(struct Vars *v)
  1209. {
  1210.   short     c,
  1211.             n;
  1212.  
  1213.   if ((n = noxrd7(v)) < 0)
  1214.     return n;
  1215.   n -= '0';
  1216.   if (n > 9)
  1217.     n -= ('a' - ':');
  1218.   if (n & ~0xF)
  1219.     return ZM_ERROR;
  1220.  
  1221.   if ((c = noxrd7(v)) < 0)
  1222.     return c;
  1223.   c -= '0';
  1224.   if (c > 9)
  1225.     c -= ('a' - ':');
  1226.   if (c & ~0xF)
  1227.     return ZM_ERROR;
  1228.  
  1229.   return (short) (n << 4 | c);
  1230. }       /*
  1231.          * End of short zgethex()
  1232.          */
  1233.  
  1234. /**********************************************************
  1235.  *      short zdlread(struct Vars *v)
  1236.  *
  1237.  * Read a byte, checking for ZMODEM escape encoding
  1238.  * including CAN*5 which represents a quick abort.
  1239.  **********************************************************/
  1240. short
  1241. zdlread(struct Vars *v)
  1242. {
  1243.   short     c;
  1244.  
  1245. again:
  1246. /*
  1247.  * Quick check for non control characters
  1248.  */
  1249.   if ((c = readock(v, v->Rxtimeout)) & 0140)
  1250.     return c;
  1251.   switch (c)
  1252.     {
  1253.       case ZDLE:
  1254.         break;
  1255.       case 023:
  1256.       case 0223:
  1257.       case 021:
  1258.       case 0221:
  1259.         goto again;
  1260.       default:
  1261.         if (v->Zctlesc && !(c & 0140))
  1262.           {
  1263.             goto again;
  1264.           }
  1265.         return c;
  1266.     }
  1267. again2:
  1268.   if ((c = readock(v, v->Rxtimeout)) < 0)
  1269.     return c;
  1270.   if (c == ZM_CAN && (c = readock(v, v->Rxtimeout)) < 0)
  1271.     return c;
  1272.   if (c == ZM_CAN && (c = readock(v, v->Rxtimeout)) < 0)
  1273.     return c;
  1274.   if (c == ZM_CAN && (c = readock(v, v->Rxtimeout)) < 0)
  1275.     return c;
  1276.   switch (c)
  1277.     {
  1278.       case ZM_CAN:
  1279.         return GOTCAN;
  1280.       case ZCRCE:
  1281.       case ZCRCG:
  1282.       case ZCRCQ:
  1283.       case ZCRCW:
  1284.         return ((short) (c | GOTOR));
  1285.       case ZRUB0:
  1286.         return 0177;
  1287.       case ZRUB1:
  1288.         return 0377;
  1289.       case 023:
  1290.       case 0223:
  1291.       case 021:
  1292.       case 0221:
  1293.         goto again2;
  1294.       default:
  1295.         if (v->Zctlesc && !(c & 0140))
  1296.           {
  1297.             goto again2;
  1298.           }
  1299.         if ((c & 0140) == 0100)
  1300.           return ((short) (c ^ 0100));
  1301.         break;
  1302.     }
  1303.   strcpy(v->Msgbuf, "MSG_BAD_ZMODEM_ESC_TXT");
  1304.   return ZM_ERROR;
  1305. }       /*
  1306.          * End of short zdlread()
  1307.          */
  1308.  
  1309. /**********************************************************
  1310.  *      short noxrd7(struct Vars *v)
  1311.  *
  1312.  * Read a character from the modem line with timeout.
  1313.  * Eat parity, XON and XOFF characters.
  1314.  **********************************************************/
  1315. short
  1316. noxrd7(struct Vars *v)
  1317. {
  1318.   short     c;
  1319.  
  1320.   for (;;)
  1321.     {
  1322.       if ((c = readock(v, v->Rxtimeout)) < 0)
  1323.         return c;
  1324.       switch (c &= 0x7F)
  1325.         {
  1326.           case ZM_XON:
  1327.           case ZM_XOFF:
  1328.             continue;
  1329.           default:
  1330.             if (v->Zctlesc && !(c & 0140))
  1331.               continue;
  1332.           case '\r':
  1333.           case '\n':
  1334.           case ZDLE:
  1335.             return c;
  1336.         }
  1337.     }
  1338. }       /*
  1339.          * short noxrd7()
  1340.          */
  1341.  
  1342. /**********************************************************
  1343.  *      void stohdr(struct Vars *v, long pos)
  1344.  *
  1345.  * Store long integer pos in Txhdr
  1346.  **********************************************************/
  1347. void
  1348. stohdr(struct Vars *v, long pos)
  1349. {
  1350.   v->Txhdr[ZP0] = pos;
  1351.   pos >>= 8;
  1352.   v->Txhdr[ZP1] = pos;
  1353.   pos >>= 8;
  1354.   v->Txhdr[ZP2] = pos;
  1355.   pos >>= 8;
  1356.   v->Txhdr[ZP3] = pos;
  1357. }       /*
  1358.          * End of void stohdr()
  1359.          */
  1360.  
  1361. /**********************************************************
  1362.  *      long rclhdr(struct Vars *v)
  1363.  *
  1364.  * Recover a long integer from a header
  1365.  **********************************************************/
  1366. long
  1367. rclhdr(struct Vars *v)
  1368. {
  1369.   long      l;
  1370.  
  1371.   l = v->Rxhdr[ZP3];
  1372.   l = (l << 8) | v->Rxhdr[ZP2];
  1373.   l = (l << 8) | v->Rxhdr[ZP1];
  1374.   l = (l << 8) | v->Rxhdr[ZP0];
  1375.   return l;
  1376. }       /*
  1377.          * End of long rclhdr()
  1378.          */
  1379.  
  1380. /**
  1381.    Find the end of the string.
  1382. **/
  1383. char     *
  1384. find_end(char *buf)
  1385. {
  1386.   while (*buf)
  1387.     buf++;
  1388.   return (buf);
  1389. }
  1390.  
  1391. /**
  1392.  Convert octal number to decimal.
  1393. **/
  1394. unsigned long
  1395. from_octal(char *buf)
  1396. {
  1397.   unsigned long value = 0;
  1398.   UBYTE     c;
  1399.  
  1400.   while (c = *buf)
  1401.     {
  1402.       if (c == ' ' || c == ',' || c == '\t' || c == '\r' || c == '\n')
  1403.         buf++;
  1404.       else
  1405.         break;
  1406.     }
  1407.  
  1408.   while (c = *buf++)
  1409.     {
  1410.       if (c >= '0' && c <= '7')
  1411.         value = (value << 3) + (c - '0');
  1412.       else
  1413.         break;
  1414.     }
  1415.  
  1416.   return (value);
  1417. }
  1418.  
  1419. /*
  1420.  * Skip all blanks.
  1421.  */
  1422. char     *
  1423. skip_chars(char *buf)
  1424. {
  1425.   UBYTE     c;
  1426.  
  1427.   while (c = *buf)
  1428.     {
  1429.       if (c == ' ' || c == ',' || c == '\t' || c == '\r' || c == '\n')
  1430.         {
  1431.           buf++;
  1432.  
  1433.           while (c = *buf)
  1434.             {
  1435.               if (c == ' ' || c == ',' || c == '\t' || c == '\r' || c == '\n')
  1436.                 buf++;
  1437.               else
  1438.                 return (buf);
  1439.             }
  1440.  
  1441.           return (buf);
  1442.         }
  1443.       else
  1444.         buf++;
  1445.     }
  1446.  
  1447.   return (buf);
  1448. }
  1449.  
  1450. /**********************************************************
  1451.  *      long XProtocolReceive(struct XPR_IO *xio)
  1452.  *
  1453.  * Main file reception routine; called by comm program
  1454.  **********************************************************/
  1455. long
  1456. XProtocolReceive(struct XPR_IO *xio)
  1457. {
  1458.   struct SetupVars *sv;
  1459.   struct Vars *v;
  1460.   UBYTE     err = FALSE;
  1461.  
  1462. /*
  1463.  * Perform common setup and initializations
  1464.  */
  1465.   if (!(v = setup(xio)))
  1466.     return XPRS_FAILURE;
  1467.  
  1468. /*
  1469.  * Remember data direction for cps rate calculation.
  1470.  */
  1471.   v->Receiving = TRUE;
  1472.   v->Tryzhdrtype = ZRINIT;
  1473.   v->Rxtimeout = 100;
  1474.  
  1475.   sv = (void *) v->io.xpr_data;
  1476.   if (sv->bufpos)
  1477.     {
  1478.       v->Modemchar = v->Modembuf;
  1479.       if (sv->buflen > sizeof(v->Modembuf))
  1480.         sv->buflen = sizeof(v->Modembuf);
  1481.       memcpy(v->Modembuf, sv->bufpos, sv->buflen);
  1482.       v->Modemcount = sv->buflen;
  1483.     }
  1484.  
  1485. /*
  1486.  * Transfer the files
  1487.  */
  1488.   if (rcvbatch(v) == ZM_ERROR)
  1489.     {
  1490.       upderr(v, "MSG_DOWNLOAD_CANCELLED_OR_TIMED_OUT");
  1491.       err = TRUE;
  1492.     }
  1493.   else
  1494.     updmsg(v, "MSG_DONE");
  1495.  
  1496. /*
  1497.  * Clean up and return
  1498.  * If an error occured, it's quite likely that there is * garbage in the
  1499.  * receive buffer we don't want the user * to see.
  1500.  */
  1501.   xpr_sflush ();
  1502.  
  1503.   FreeMem(v->Filebuf, v->Filebufmax);
  1504.   FreeMem(v, (long) sizeof(struct Vars));
  1505.  
  1506.   return (err) ? XPRS_FAILURE : XPRS_SUCCESS;
  1507. }       /*
  1508.          * End of long XProtocolReceive()
  1509.          */
  1510.  
  1511. /**********************************************************
  1512.  *      short rcvbatch(struct Vars *v)
  1513.  *
  1514.  * Start the batch transfer
  1515.  **********************************************************/
  1516. short
  1517. rcvbatch(struct Vars *v)
  1518. {
  1519.   switch (tryz(v))
  1520.     {
  1521.       case ZCOMPL:
  1522.         return OK;
  1523.       case ZFILE:
  1524.         if (rzfiles(v) == OK)
  1525.           return OK;
  1526.     }
  1527.   canit(v);
  1528.   return ZM_ERROR;
  1529. }       /*
  1530.          * End of short rcvbatch()
  1531.          */
  1532.  
  1533. /**********************************************************
  1534.  *      short tryz(struct Vars *v)
  1535.  *
  1536.  * Negotiate with sender to start a file transfer
  1537.  **********************************************************/
  1538. short
  1539. tryz(struct Vars *v)
  1540. {
  1541.   short     n,
  1542.             errors = 0;
  1543.   for (n = v->ErrorLimit; --n >= 0;)
  1544.     {
  1545.  /*
  1546.   * Set max frame length and capability flags
  1547.   */
  1548.       stohdr(v, (long) v->Tframlen);
  1549.       v->Txhdr[ZF0] = CANFC32 | CANFDX | CANOVIO;
  1550.  
  1551.       if (v->Zctlesc)
  1552.         v->Txhdr[ZF0] |= TESCCTL;
  1553.  
  1554.       zshhdr(v, v->Tryzhdrtype);
  1555.       sendbuf(v);
  1556.  
  1557.       if (v->Tryzhdrtype == ZSKIP)      /*
  1558.                                          * Don't skip too far.
  1559.                                          */
  1560.         v->Tryzhdrtype = ZRINIT;        /*
  1561.                                          * CAF 8-21-87
  1562.                                          */
  1563.  
  1564.     again:
  1565.  /*
  1566.   * Check for abort from comm program
  1567.   */
  1568.  
  1569.           if ( xpr_chkabort() )
  1570.             {
  1571.               zshhdr(v, ZABORT);
  1572.               sendbuf(v);
  1573.               return ZM_ERROR;
  1574.             }
  1575.  
  1576.       switch (zgethdr(v))
  1577.         {
  1578.           case ZFILE:   /*
  1579.                          * File name and info packet
  1580.                          */
  1581.             v->Zconv = v->Rxhdr[ZF0];   /*
  1582.                                          * Suggested txt mode; ZCNL = text,
  1583.                                          */
  1584.        /*
  1585.         * ZCBIN = binary, 0 = don't know.
  1586.         */
  1587.             v->Zmanag = v->Rxhdr[ZF1];  /*
  1588.                                          * Suggested file management mode.
  1589.                                          */
  1590.             v->Ztrans = v->Rxhdr[ZF2];  /*
  1591.                                          * Suggested file transport mode.
  1592.                                          */
  1593.             v->Tryzhdrtype = ZRINIT;
  1594.  
  1595.             if (zrdata(v, v->Pktbuf, v->ksize) == GOTCRCW)
  1596.               return ZFILE;
  1597.             zshhdr(v, ZNAK);    /*
  1598.                                  * Packet mangled, ask for retry
  1599.                                  */
  1600.             sendbuf(v);
  1601.             goto again;
  1602.           case ZSINIT:          /*
  1603.                                  * Special attention-grabbing string to use
  1604.                                  * to
  1605.                                  */
  1606.             v->Zctlesc = TESCCTL & v->Rxhdr[ZF0];
  1607.        /*
  1608.         * interrupt sender
  1609.         */
  1610.             if (zrdata(v, v->Attn, ZATTNLEN) == GOTCRCW)
  1611.               zshhdr(v, ZACK);
  1612.             else
  1613.               zshhdr(v, ZNAK);
  1614.             sendbuf(v);
  1615.             goto again;
  1616.           case ZFREECNT:        /*
  1617.                                  * Sender wants to know how much room we've
  1618.                                  * got
  1619.                                  */
  1620.             stohdr(v, getfree(v));
  1621.             zshhdr(v, ZACK);
  1622.             sendbuf(v);
  1623.             goto again;
  1624.           case ZCOMMAND:        /*
  1625.                                  * Sender wants us to do remote commands,
  1626.                                  */
  1627.        /*
  1628.         * but we don't do requests.
  1629.         */
  1630.  
  1631.             if (zrdata(v, v->Pktbuf, v->ksize) == GOTCRCW)
  1632.               {
  1633.                 sprintf(v->Msgbuf, "MSG_IGNORING_COMMAND", v->Pktbuf);
  1634.                 upderr(v, v->Msgbuf);   /*
  1635.                                          * Ignore and report all uploaded
  1636.                                          * commands
  1637.                                          */
  1638.                 stohdr(v, 0L);  /*
  1639.                                  * whilst telling sender they worked;
  1640.                                  */
  1641.                 do
  1642.                   {
  1643.                     zshhdr(v, ZCOMPL);  /*
  1644.                                          * paranoia can be good for you...
  1645.                                          */
  1646.                     sendbuf(v);
  1647.                   }
  1648.                 while (++errors < v->ErrorLimit && zgethdr(v) != ZFIN);
  1649.                 ackbibi(v);
  1650.                 return ZCOMPL;
  1651.               }
  1652.             else
  1653.               zshhdr(v, ZNAK);
  1654.             sendbuf(v);
  1655.             goto again;
  1656.           case ZCOMPL:
  1657.             goto again;
  1658.           case ZFIN:    /*
  1659.                          * Sender has ended batch
  1660.                          */
  1661.             ackbibi(v);
  1662.             return ZCOMPL;
  1663.           case ZCAN:
  1664.           case RCDO:
  1665.             upderr(v, v->Msgbuf);
  1666.             return ZM_ERROR;
  1667.         }
  1668.     }
  1669.   return ZM_ERROR;
  1670. }       /*
  1671.          * End of short tryz()
  1672.          */
  1673.  
  1674. /**********************************************************
  1675.  *      short rzfiles(struct Vars *v)
  1676.  *
  1677.  * Receive a batch of files
  1678.  **********************************************************/
  1679. short
  1680. rzfiles(struct Vars *v)
  1681. {
  1682.   struct SetupVars *sv;
  1683.   short     c;
  1684.  
  1685. /*
  1686.  * Keep receiving files until end of batch or error
  1687.  */
  1688.   while (TRUE)
  1689.     {
  1690.       switch (c = rzfile(v))
  1691.         {
  1692.           case ZEOF:
  1693.           case ZSKIP:
  1694.             switch (tryz(v))
  1695.               {
  1696.                 case ZCOMPL:
  1697.                   return OK;
  1698.                 default:
  1699.                   return ZM_ERROR;
  1700.                 case ZFILE:
  1701.                   break;
  1702.               }
  1703.             break;
  1704.           default:
  1705.             bfclose(v);
  1706.             sv = (void *) v->io.xpr_data;
  1707.             if (*sv->option_k == 'N' )
  1708.               {
  1709.                 updmsg(v, "MSG_DELETING_PARTIALLY_RECEIVED_FILE");
  1710.                 unlink(v->Filename);
  1711.               }
  1712.             else
  1713.               updmsg(v, "MSG_KEEPING_PARTIALLY_RECEIVED_FILE");
  1714.             return c;
  1715.         }
  1716.     }
  1717. }       /*
  1718.          * End of short rzfiles()
  1719.          */
  1720.  
  1721. /**********************************************************
  1722.  *      short rzfile(struct Vars *v)
  1723.  *
  1724.  * Receive one file; file name packet already read into
  1725.  * Pktbuf by tryz()
  1726.  **********************************************************/
  1727. short
  1728. rzfile(struct Vars *v)
  1729. {
  1730.   short     c,
  1731.             n;
  1732.   long      result,
  1733.             abort = 0;
  1734.  
  1735. /*
  1736.  * Process file name packet; either open file and prepare to receive, * or
  1737.  * tell us to skip this one.
  1738.  */
  1739.   if (procheader(v) == ZM_ERROR)
  1740.     return v->Tryzhdrtype = ZSKIP;
  1741.  
  1742.   n = v->ErrorLimit;
  1743.   v->Rxbytes = v->Strtpos;
  1744.   v->Eofseen = FALSE;
  1745.  
  1746. /*
  1747.  * Receive ZDATA frames until finished
  1748.  */
  1749.   while (TRUE)
  1750.     {
  1751.       stohdr(v, v->Rxbytes);    /*
  1752.                                  * Tell sender where to start frame
  1753.                                  */
  1754.       zshhdr(v, ZRPOS);
  1755.       sendbuf(v);
  1756.     nxthdr:
  1757.  /*
  1758.   * Check for abort from comm program
  1759.   */
  1760.           if (abort)
  1761.             {
  1762.               result = abort;
  1763.               abort = 0;
  1764.             };
  1765.  
  1766.      /*
  1767.       * Cancel transmission.
  1768.       */
  1769.           if (result || xpr_chkabort() )
  1770.             {
  1771.               zshhdr(v, ZABORT);
  1772.               sendbuf(v);
  1773.             };
  1774.  
  1775.       switch (c = zgethdr(v))   /*
  1776.                                  * Wait for frame header
  1777.                                  */
  1778.         {
  1779.           default:
  1780.             return ZM_ERROR;
  1781.           case ZFIN:
  1782.             zshhdr(v, ZCOMPL);
  1783.             sendbuf(v);
  1784.             return ZFIN;
  1785.           case ZNAK:
  1786.           case TIMEOUT:
  1787.             if (--n < 0)
  1788.               return ZM_ERROR;
  1789.             v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_TIMEOUTS;
  1790.             sprintf(find_end(v->Msgbuf), "MSG_AT %ld RETRIES %ld LEFT",
  1791.                       v->Rxbytes, (long) n);
  1792.             v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  1793.             ++v->xpru.xpru_timeouts;
  1794.             display_update(&v->xpru);
  1795.             continue;
  1796.           case ZFILE:   /*
  1797.                          * Sender didn't see our ZRPOS yet; try again
  1798.                          */
  1799.  
  1800.             zrdata(v, v->Pktbuf, v->ksize);     /*
  1801.                                                  * Read and discard
  1802.                                                  * redundant
  1803.                                                  */
  1804.             continue;   /*
  1805.                          * filename packet
  1806.                          */
  1807.           case ZEOF:    /*
  1808.                          * End of file data
  1809.                          */
  1810.             if (v->Rxpos != v->Rxbytes)         /*
  1811.                                                  * We aren't in sync; go
  1812.                                                  * back
  1813.                                                  */
  1814.               {
  1815.                 sprintf(v->Msgbuf, "MSG_BAD_EOF:%ld %ld",
  1816.                           v->Rxbytes, v->Rxpos);
  1817.                 upderr(v, v->Msgbuf);
  1818.                 continue;
  1819.               }
  1820.             bfclose(v);         /*
  1821.                                  * All done; close file
  1822.                                  */
  1823.             updmsg(v, "MSG_EOF_RECEIVED");
  1824.             return c;
  1825.           case ZM_ERROR:   /*
  1826.                          * Too much garbage while waiting for frame header
  1827.                          */
  1828.             if (--n < 0)
  1829.               return ZM_ERROR;
  1830.             v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_ERRORS;
  1831.             sprintf(find_end(v->Msgbuf), "MSG_AT %ld RETRIES %ld LEFT",
  1832.                       v->Rxbytes, (long) n);
  1833.             v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  1834.             ++v->xpru.xpru_errors;
  1835.             display_update(&v->xpru);
  1836.             zmputs(v, v->Attn);
  1837.             continue;
  1838.           case ZSKIP:
  1839.             v->Modtime = 1;
  1840.             bfclose(v);
  1841.             upderr(v, "MSG_SKIP_COMMAND_RECEIVED");
  1842.             return (c);
  1843.           case ZDATA:   /*
  1844.                          * More file data packets forthcoming
  1845.                          */
  1846.             if (v->Rxpos != v->Rxbytes)         /*
  1847.                                                  * We aren't in sync; go
  1848.                                                  * back
  1849.                                                  */
  1850.               {
  1851.                 if (--n < 0)
  1852.                   return ZM_ERROR;
  1853.                 v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_ERRORS;
  1854.                 sprintf(v->Msgbuf, "MSG_DATA_AT %ld BAD_POSITION %ld",
  1855.                           v->Rxbytes, v->Rxpos);
  1856.                 v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  1857.                 ++v->xpru.xpru_errors;
  1858.                 display_update(&v->xpru);
  1859.                 zmputs(v, v->Attn);
  1860.                 continue;
  1861.               }
  1862.        /*
  1863.         * Receive file data packet(s)
  1864.         */
  1865.           moredata:
  1866.        /*
  1867.         * Check for abort from comm program
  1868.         */
  1869.                 if( (abort = xpr_chkabort()) )
  1870.                   {
  1871.                     zshhdr(v, ZABORT);
  1872.                     sendbuf(v);
  1873.                     upderr(v, "MSG_TRANSFER_CANCELED");
  1874.                     return ZM_ERROR;
  1875.                   };
  1876.             switch (c = zrdata(v, v->Pktbuf, v->ksize))
  1877.               {
  1878.                 case ZCAN:
  1879.                 case RCDO:
  1880.                   upderr(v, "MSG_TRANSFER_CANCELED");
  1881.                   return ZM_ERROR;
  1882.                 case ZM_ERROR:     /*
  1883.                                  * CRC error or packet too long
  1884.                                  */
  1885.                   if (--n < 0)
  1886.                     return ZM_ERROR;
  1887.                   v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_ERRORS;
  1888.                   sprintf(find_end(v->Msgbuf), "MSG_AT %ld RETRIES %ld LEFT",
  1889.                             v->Rxbytes, (long) n);
  1890.                   v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  1891.                   ++v->xpru.xpru_errors;
  1892.                   display_update(&v->xpru);
  1893.                   zmputs(v, v->Attn);
  1894.                   continue;
  1895.                 case TIMEOUT:
  1896.                   if (--n < 0)
  1897.                     return ZM_ERROR;
  1898.                   v->xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_TIMEOUTS;
  1899.                   sprintf(find_end(v->Msgbuf), "MSG_AT %ld RETRIES %ld LEFT",
  1900.                             v->Rxbytes, (long) n);
  1901.                   v->xpru.xpru_errormsg = (char *) v->Msgbuf;
  1902.                   ++v->xpru.xpru_timeouts;
  1903.                   display_update(&v->xpru);
  1904.                   continue;
  1905.                 case GOTCRCW:   /*
  1906.                                  * Sender says it's waiting for an ACK
  1907.                                  */
  1908.                   n = v->ErrorLimit;
  1909.                   if (putsec(v) == ZM_ERROR)
  1910.                     return ZM_ERROR;
  1911.                   stohdr(v, v->Rxbytes);
  1912.                   zshhdr(v, ZACK);
  1913.                   sendbuf(v);
  1914.                   goto nxthdr;
  1915.                 case GOTCRCQ:   /*
  1916.                                  * Sender says it's not waiting,
  1917.                                  */
  1918.              /*
  1919.               * but ACK anyway (rarely used)
  1920.               */
  1921.                   n = v->ErrorLimit;
  1922.                   if (putsec(v) == ZM_ERROR)
  1923.                     return ZM_ERROR;
  1924.                   stohdr(v, v->Rxbytes);
  1925.                   zshhdr(v, ZACK);
  1926.                   sendbuf(v);
  1927.                   goto moredata;
  1928.                 case GOTCRCG:   /*
  1929.                                  * Sender says keep receiving, there's more
  1930.                                  * coming
  1931.                                  */
  1932.                   n = v->ErrorLimit;
  1933.                   if (putsec(v) == ZM_ERROR)
  1934.                     return ZM_ERROR;
  1935.                   goto moredata;
  1936.                 case GOTCRCE:   /*
  1937.                                  * Sender says this is the last packet
  1938.                                  */
  1939.                   n = v->ErrorLimit;
  1940.                   if (putsec(v) == ZM_ERROR)
  1941.                     return ZM_ERROR;
  1942.                   goto nxthdr;
  1943.               }
  1944.         }
  1945.     }
  1946. }       /*
  1947.          * End of short rzfile()
  1948.          */
  1949.  
  1950. /************************ZM_**********************************
  1951.  *      short procheader(struct Vars *v)
  1952.  *
  1953.  * Process file name & info packet; either open file and
  1954.  * prepare to receive, or return ZM_ERROR if we should skip
  1955.  * this one for some reason
  1956.  **********************************************************/
  1957. short
  1958. procheader(struct Vars *v)
  1959. {
  1960.   struct SetupVars *sv;
  1961.   UBYTE    *p,
  1962.            *openmode,
  1963.             buff[PATHLEN];
  1964.   long      n;
  1965.  
  1966.   openmode = "w";
  1967.   v->Strtpos = 0;
  1968.  
  1969. /*
  1970.  * Extract expected filesize from file info packet, if given
  1971.  */
  1972.   v->Fsize = -1;
  1973.   p = find_end(v->Pktbuf) + 1;
  1974.  
  1975.   if (*p)
  1976.     {
  1977.       char     *index,
  1978.                *ptr;
  1979.  
  1980.       index = skip_chars(ptr = p);
  1981.  
  1982.       v->Fsize = atol(ptr);
  1983.  
  1984.       index = skip_chars(ptr = index);
  1985.  
  1986.       v->Modtime = from_octal(ptr);
  1987.  
  1988.       skip_chars(ptr = index);
  1989.  
  1990.       v->Bits = from_octal(ptr);
  1991.  
  1992.       v->SetAttributes = TRUE;
  1993.     }
  1994.   else
  1995.     {
  1996.       v->Modtime = 0;
  1997.       v->Bits = 0;
  1998.       v->SetAttributes = FALSE;
  1999.     }
  2000.  
  2001. /*
  2002.  * If option RY set, use full received file path
  2003.  */
  2004.   sv = (void *) v->io.xpr_data;
  2005.   if (*sv->option_r == 'Y')
  2006.     strcpy(v->Filename, v->Pktbuf);
  2007.   else
  2008.     {
  2009.  /*
  2010.   * else use the default directory path specified in the setup options
  2011.   */
  2012.       strcpy(v->Filename, sv->option_p);
  2013.       p = v->Filename + strlen(v->Filename) - 1;
  2014.       if (p >= v->Filename && *p != '/' && *p != ':')
  2015.         *++p = '/';
  2016.       *++p = '\0';
  2017.  /*
  2018.   * Append the filename from the file info packet; ignore anything before *
  2019.   * last /, \, or : in filename (received directory path is ignored)
  2020.   */
  2021.       p = find_end(v->Pktbuf);  /*
  2022.                                  * start at end and scan back
  2023.                                  */
  2024.  /*
  2025.   * to start of name
  2026.   */
  2027.       while (p >= v->Pktbuf && *p != '/' && *p != '\\' && *p != ':')
  2028.         --p;
  2029.       strcat(v->Filename, ++p);
  2030.     }
  2031.  
  2032. /*
  2033.  * Make sure we have room for file; skip it if not.
  2034.  */
  2035.  
  2036.   if (v->Fsize > getfree(v))
  2037.     {
  2038.       sprintf(v->Msgbuf, "MSG_INSUFFICIENT_DISK_SPACE Size:%ld Avail:%ld",
  2039.                 v->Fsize, getfree(v));
  2040.       upderr(v, v->Msgbuf);
  2041.       v->Noroom = TRUE;
  2042.       return ZM_ERROR;
  2043.     }
  2044.  
  2045. /*
  2046.  * Display name of file being received for user
  2047.  */
  2048.   v->xpru.xpru_updatemask = XPRU_FILENAME;
  2049.   v->xpru.xpru_filename = (char *) v->Filename;
  2050.   display_update(&v->xpru);
  2051.  
  2052. /*
  2053.  * If a file with this name already exists, handle in * accordance with O
  2054.  * option
  2055.  */
  2056.   if (exist(v))
  2057.     {
  2058.       switch (*sv->option_o)
  2059.         {
  2060.           case 'N':     /*
  2061.                          * Don't overwrite; change name to prevent collision
  2062.                          */
  2063.             strcpy(buff, v->Filename);
  2064.             strcat(v->Filename, ".dup");
  2065.             n = 2;
  2066.             while (exist(v))
  2067.               {
  2068.                 sprintf(v->Filename, "%s.dup%ld", buff, n);
  2069.                 ++n;
  2070.               }
  2071.        /*
  2072.         * Update filename display to show new name
  2073.         */
  2074.             display_update(&v->xpru);
  2075.             break;
  2076.           case 'R':     /*
  2077.                          * Resume transfer from current end of file
  2078.                          */
  2079.             openmode = "a";
  2080.             v->Strtpos = xpr_finfo(v->Filename, 1L);
  2081.             break;
  2082.           case 'S':     /*
  2083.                          * Skip it
  2084.                          */
  2085.             upderr(v, "MSG_FILE_ALREADY_EXISTS");
  2086.             return ZM_ERROR;
  2087.        /*
  2088.         * Else 'Y', go ahead and overwrite it (openmode = w)
  2089.         */
  2090.         }
  2091.     }
  2092.  
  2093. /*
  2094.  * Set text/binary mode according to options before opening file
  2095.  */
  2096.   set_textmode(v);
  2097.  
  2098. /*
  2099.  * Figure out file translation mode to use; either binary (verbatim *
  2100.  * transfer) or ASCII (perform end-of-line conversions).  If user has *
  2101.  * specified a mode (TY or TN), that's what we use.  If user says use *
  2102.  * sender's suggestion (T?), set mode according to Zconv flag.  If neither *
  2103.  * side specifies, default to binary mode.
  2104.  */
  2105.   v->Thisbinary = v->Rxbinary || !v->Rxascii;
  2106.   if (!v->Rxbinary && v->Zconv == ZCNL)
  2107.     v->Thisbinary = FALSE;
  2108.   if (!v->Rxascii && v->Zconv == ZCBIN)
  2109.     v->Thisbinary = TRUE;
  2110.  
  2111. /*
  2112.  * Open the file (finally)
  2113.  */
  2114.   if (!(v->File = bfopen(v, openmode)))
  2115.     {
  2116.       ++v->Errcnt;
  2117.       upderr(v, "MSG_CANT_OPEN_FILE");
  2118.       return ZM_ERROR;
  2119.     }
  2120.   GetSysTime(&v->Starttime);
  2121.   v->BytesReceived = 0;
  2122.  
  2123. /*
  2124.  * Initialize comm program transfer status display
  2125.  */
  2126.   v->xpru.xpru_updatemask = XPRU_PROTOCOL | XPRU_FILESIZE | XPRU_MSG
  2127.     | XPRU_BLOCKS | XPRU_ERRORS | XPRU_TIMEOUTS | XPRU_BLOCKCHECK
  2128.     | XPRU_BYTES | XPRU_ELAPSEDTIME;
  2129.   v->xpru.xpru_protocol = "ZModem";
  2130.   v->xpru.xpru_filesize = v->Fsize;
  2131.   v->xpru.xpru_msg = (v->Thisbinary) ? "MSG_RECEIVING_BINARY_FILE"
  2132.     : "MSG_RECEIVING_TEXT_FILE";
  2133.   v->xpru.xpru_blocks = v->xpru.xpru_errors = v->xpru.xpru_timeouts = 0;
  2134.   v->xpru.xpru_blockcheck = v->Crc32 ? "CRC-32" : "CRC-16";
  2135.   v->xpru.xpru_bytes = v->Strtpos;
  2136.   v->xpru.xpru_blocksize = v->ksize;
  2137.   update_rate(v);
  2138.   display_update(&v->xpru);
  2139.  
  2140.   return OK;
  2141. }       /*
  2142.          * End of short procheader()
  2143.          */
  2144.  
  2145. /**********************************************************
  2146.  *      short putsec(struct Vars *v)
  2147.  *
  2148.  * Writes the received file data to the output file.
  2149.  * If in ASCII mode, stops writing at first ^Z, and converts all
  2150.  * \r\n pairs or solo \r's to \n's.
  2151.  **********************************************************/
  2152. short
  2153. putsec(struct Vars *v)
  2154. {
  2155.   char      nl = '\n';
  2156.   UBYTE    *p;
  2157.   short     n;
  2158.  
  2159. /*
  2160.  * If in binary mode, write it out verbatim
  2161.  */
  2162.   if (v->Thisbinary)
  2163.     {
  2164.       if (bfwrite(v, v->Pktbuf, (long) v->Rxcount) != v->Rxcount)
  2165.         goto diskfull;
  2166.  /*
  2167.   * If in text mode, perform end-of-line cleanup
  2168.   */
  2169.     }
  2170.   else
  2171.     {
  2172.       if (v->Eofseen)
  2173.         return OK;
  2174.       for (p = v->Pktbuf, n = v->Rxcount; --n >= 0; ++p)
  2175.         {
  2176.           if (*p == ZM_CPMEOF)
  2177.             {
  2178.               v->Eofseen = TRUE;
  2179.               return OK;
  2180.             }
  2181.           else if (*p != '\n' && v->Lastsent == '\r')
  2182.             {
  2183.               if (bfwrite(v, &nl, 1L) != 1)
  2184.                 goto diskfull;
  2185.             }
  2186.           if (*p != '\r' && bfwrite(v, p, 1L) != 1)
  2187.             goto diskfull;
  2188.           v->Lastsent = *p;
  2189.         }
  2190.     }
  2191.  
  2192. /*
  2193.  * Update comm program status display
  2194.  */
  2195.   v->xpru.xpru_updatemask = XPRU_BLOCKS | XPRU_BLOCKSIZE | XPRU_BYTES
  2196.     | XPRU_ELAPSEDTIME | XPRU_BLOCKCHECK;
  2197.   ++v->xpru.xpru_blocks;
  2198.   v->xpru.xpru_blocksize = v->Rxcount;
  2199.   v->xpru.xpru_bytes = v->Rxbytes += v->Rxcount;
  2200.   v->xpru.xpru_blockcheck = v->Crc32 ? "CRC-32" : "CRC-16";
  2201.   update_rate(v);
  2202.   display_update(&v->xpru);
  2203.  
  2204.   return OK;
  2205.  
  2206. diskfull:
  2207.   upderr(v, "MSG_ERROR_WRITING_FILE");
  2208.   v->Noroom = TRUE;
  2209.   return ZM_ERROR;
  2210. }       /*
  2211.          * End of short putsec()
  2212.          */
  2213.  
  2214. /**********************************************************
  2215.  *      void ackbibi(struct Vars *v)
  2216.  *
  2217.  * End of batch transmission; disengage cleanly from sender
  2218.  **********************************************************/
  2219. void
  2220. ackbibi(struct Vars *v)
  2221. {
  2222.   short     n;
  2223.  
  2224.   stohdr(v, 0L);
  2225.   for (n = 4; --n;)
  2226.     {
  2227.       zshhdr(v, ZFIN);
  2228.       sendbuf(v);
  2229.       switch (readock(v, 100))
  2230.         {
  2231.           case 'O':
  2232.             readock(v, 1);      /*
  2233.                                  * Discard 2nd 'O'
  2234.                                  */
  2235.           case TIMEOUT:
  2236.           case RCDO:
  2237.             return;
  2238.         }
  2239.     }
  2240. }       /*
  2241.          * End of void ackbibi()
  2242.          */
  2243. /*
  2244.  * End of Receive.c source
  2245.  */
  2246. /**********************************************************************
  2247.  * Send.c: File transmission routines for xprzmodem.library;
  2248.  * Original Version 2.10, 12 February 1991, by Rick Huebner.
  2249.  * Based closely on Chuck Forsberg's sz.c example ZModem code,
  2250.  * but too pervasively modified to even think of detailing the changes.
  2251.  * Released to the Public Domain; do as you like with this code.
  2252.  *
  2253.  * Version 2.50, 15 November 1991, CRC-32 additions by William M. Perkins.
  2254.  * Version 2.51 29, January 1992, RX_timout fix by John Tillema
  2255.  * Version 2.52   6 March 1992, Very minor fix with compiled 020 library
  2256.  *               by William M. Perkins.
  2257.  * Version 2.53, 28 June 1993, several additions by Olaf `Olsen' Barthel
  2258.  **********************************************************************/
  2259.  
  2260. /*
  2261.  * Convert decimal to octal value.
  2262.  */
  2263. VOID
  2264. to_octal(STRPTR buf, ULONG value)
  2265. {
  2266.   UBYTE     buffer[20];
  2267.   short     i = 1;
  2268.  
  2269.   while (value)
  2270.     {
  2271.       buffer[i++] = '0' + (value & 7);
  2272.  
  2273.       value >>= 3;
  2274.     }
  2275.  
  2276.   do
  2277.     *buf++ = buffer[--i];
  2278.   while (i);
  2279.  
  2280.   *buf = 0;
  2281. }
  2282.  
  2283. /**********************************************************
  2284.  *      long XProtocolSend(struct XPR_IO *xio)
  2285.  *
  2286.  * Main file transmission routine; called by comm program
  2287.  **********************************************************/
  2288. long
  2289. XProtocolSend(struct XPR_IO *xio)
  2290. {
  2291.   struct Vars *v;
  2292.   short     err;
  2293.  
  2294. /*
  2295.  * Perform common setup and initializations
  2296.  */
  2297.   if (!(v = setup(xio)))
  2298.     return XPRS_FAILURE;
  2299.  
  2300. /*
  2301.  * was 600, set to 300 to fix so it uploads correctly
  2302.  */
  2303.   v->Rxtimeout = 300;
  2304.   v->Wantfcs32 = TRUE;
  2305.   v->Rxflags = 0;
  2306.   v->Receiving = FALSE;
  2307.  
  2308. /*
  2309.  * Transfer the files
  2310.  */
  2311.   zmputs(v, "rz\r");
  2312.   stohdr(v, 0L);
  2313.   zshhdr(v, ZRQINIT);
  2314.   sendbuf(v);
  2315.   if (getzrxinit(v) == ZM_ERROR)
  2316.     upderr(v, "MSG_UPLOAD_CANCELED_TXT");
  2317.   else
  2318.     sendbatch(v);
  2319.  
  2320. /*
  2321.  * Clean up and return
  2322.  */
  2323.   if (err = v->Errcnt)
  2324.     upderr(v, "MSG_FILES_SKIPPED_DUE_TO_ERRORS_TXT");
  2325.   else
  2326.     updmsg(v, "MSG_DONE_TXT");
  2327.   FreeMem(v->Filebuf, v->Filebufmax);
  2328.   FreeMem(v, (long) sizeof(struct Vars));
  2329.  
  2330.   return (err) ? XPRS_FAILURE : XPRS_SUCCESS;
  2331. }       /*
  2332.          * End of long XProtocolSend()
  2333.          */
  2334.  
  2335. /**********************************************************
  2336.  *      short getzrxinit(struct Vars *v)
  2337.  *
  2338.  * Negotiate with receiver to start a file transfer
  2339.  **********************************************************/
  2340. short
  2341. getzrxinit(struct Vars *v)
  2342. {
  2343.   short     n;
  2344.  
  2345.   for (n = v->ErrorLimit; --n >= 0;)
  2346.     {
  2347.  /*
  2348.   * Check for abort from comm program
  2349.   */
  2350.       if ( xpr_chkabort() )
  2351.         {
  2352.           canit(v);     /*
  2353.                          * Receiver does not respond to ZABORT.
  2354.                          */
  2355.           return ZM_ERROR;
  2356.         }
  2357.       switch (zgethdr(v))
  2358.         {
  2359.           case ZCHALLENGE:      /*
  2360.                                  * Echo receiver's challenge number
  2361.                                  */
  2362.             stohdr(v, v->Rxpos);
  2363.             zshhdr(v, ZACK);
  2364.             sendbuf(v);
  2365.             continue;
  2366.           case ZCOMMAND:        /*
  2367.                                  * They didn't see our ZRQINIT; try again
  2368.                                  */
  2369.             stohdr(v, 0L);
  2370.             zshhdr(v, ZRQINIT);
  2371.             sendbuf(v);
  2372.             continue;
  2373.           case ZRINIT:          /*
  2374.                                  * Receiver ready; get transfer parameters
  2375.                                  */
  2376.             v->Rxflags = 0xFF & v->Rxhdr[ZF0];
  2377.             v->Txfcs32 = (v->Wantfcs32 && (v->Rxflags & CANFC32));
  2378.             v->Zctlesc |= v->Rxflags & TESCCTL;
  2379.             v->Rxbuflen = ((USHORT) v->Rxhdr[ZP1] << 8) | v->Rxhdr[ZP0];
  2380.        /*
  2381.         * Use shortest of the two side's max frame lengths
  2382.         */
  2383.             if (v->Tframlen && (!v->Rxbuflen || v->Tframlen < v->Rxbuflen))
  2384.               v->Rxbuflen = v->Tframlen;
  2385.             return (sendzsinit(v));
  2386.           case ZCAN:
  2387.           case RCDO:
  2388.           case TIMEOUT:
  2389.             upderr(v, v->Msgbuf);
  2390.             return ZM_ERROR;
  2391.           case ZRQINIT:
  2392.             if (v->Rxhdr[ZF0] == ZCOMMAND)
  2393.               continue;
  2394.        /*
  2395.         * fallthrough...
  2396.         */
  2397.           default:
  2398.             zshhdr(v, ZNAK);
  2399.             sendbuf(v);
  2400.             continue;
  2401.         }
  2402.     }
  2403.   return ZM_ERROR;
  2404. }       /*
  2405.          * End of short getzrxinit()
  2406.          */
  2407.  
  2408. /*
  2409.  * Send send-init information
  2410.  */
  2411. short
  2412. sendzsinit(struct Vars *v)
  2413. {
  2414.   if (v->Attn[0] == '\0' && (!v->Zctlesc || (v->Rxflags & TESCCTL)))
  2415.     return OK;
  2416.   else
  2417.     {
  2418.       short     c,
  2419.                 errors = 0;
  2420.  
  2421.       for (;;)
  2422.         {
  2423.           stohdr(v, 0L);
  2424.           if (v->Zctlesc)
  2425.             {
  2426.               v->Txhdr[ZF0] |= TESCCTL;
  2427.               zshhdr(v, ZSINIT);
  2428.             }
  2429.           else
  2430.             zsbhdr(v, ZSINIT);
  2431.  
  2432.           v->Outbuf[0] = 0;
  2433.           zsdata(v, 1, ZCRCW);
  2434.  
  2435.           c = zgethdr(v);
  2436.           switch (c)
  2437.             {
  2438.               case ZCAN:
  2439.                 return ZM_ERROR;
  2440.               case ZACK:
  2441.                 return OK;
  2442.               default:
  2443.                 if (++errors > v->ErrorLimit)
  2444.                   return ZM_ERROR;
  2445.                 continue;
  2446.             }
  2447.         }
  2448.     }
  2449. }       /*
  2450.          * End of short sendzsinit()
  2451.          */
  2452.  
  2453. /**********************************************************
  2454.  *      void sendbatch(struct Vars *v)
  2455.  *
  2456.  * Send a batch of files
  2457.  **********************************************************/
  2458. void
  2459. sendbatch(struct Vars *v)
  2460. {
  2461.   UBYTE     single,
  2462.             done = FALSE;
  2463.   long      fstate;
  2464.  
  2465.       single = FALSE;
  2466.       fstate = xpr_ffirst(v->Filename, v->io.xpr_filename);
  2467.       if (!fstate)
  2468.         {
  2469.           upderr(v, "MSG_NO_FILES_MATCH_TEMPLATE_TXT");
  2470.           return;
  2471.         }
  2472.  
  2473. /*
  2474.  * If using templates, keep getting names & sending until done
  2475.  */
  2476.   while (!done)
  2477.     {
  2478.       if (sendone(v) == ZM_ERROR)
  2479.         return;
  2480.       if (single)
  2481.         break;
  2482.       fstate = xpr_fnext(fstate, v->Filename, v->io.xpr_filename);
  2483.       done = !fstate;
  2484.     }
  2485.  
  2486. /*
  2487.  * End batch and return; if we never got started, just cancel receiver
  2488.  */
  2489.   if (v->Filcnt)
  2490.     saybibi(v);
  2491.   else
  2492.     canit(v);
  2493. }       /*
  2494.          * End of void sendbatch()
  2495.          */
  2496.  
  2497. /**********************************************************
  2498.  *      short sendone(struct Vars *v)
  2499.  *
  2500.  * Send the file named in v->Filename
  2501.  **********************************************************/
  2502. short
  2503. sendone(struct Vars *v)
  2504. {
  2505.   struct SetupVars *sv;
  2506.  
  2507. /*
  2508.  * Display name of file being sent for user
  2509.  */
  2510.   v->xpru.xpru_updatemask = XPRU_FILENAME;
  2511.   v->xpru.xpru_filename = v->Filename;
  2512.   display_update(&v->xpru);
  2513.  
  2514. /*
  2515.  * Set text/binary mode according to options before opening file
  2516.  */
  2517.   set_textmode(v);
  2518.  
  2519. /*
  2520.  * Open the file, if possible
  2521.  */
  2522.   if (!(v->File = bfopen(v, "r")))
  2523.     {
  2524.       ++v->Errcnt;
  2525.       upderr(v, "MSG_CANT_OPEN_FILE_TXT");
  2526.       return OK;        /*
  2527.                          * pass over it, there may be others
  2528.                          */
  2529.     }
  2530.   ++v->Filcnt;
  2531.   GetSysTime(&v->Starttime);
  2532.   v->BytesSent = 0;
  2533.  
  2534. /*
  2535.  * Kick off the file transfer
  2536.  */
  2537.   sv = (void *) v->io.xpr_data;
  2538.   switch (sendname(v))
  2539.     {
  2540.       case ZM_ERROR:
  2541.         ++v->Errcnt;
  2542.         return ZM_ERROR;
  2543.       case OK:
  2544.         bfclose(v);
  2545.    /*
  2546.     * File sent; if option DY, delete file after sending
  2547.     */
  2548.         if (*sv->option_d == 'Y' )
  2549.           {
  2550.             updmsg(v, "MSG_DELETING_FILE_AFTER_SEND_TXT");
  2551.             unlink(v->Filename);
  2552.           }
  2553.         break;
  2554.     }
  2555.   return OK;
  2556. }       /*
  2557.          * End of short sendone()
  2558.          */
  2559.  
  2560. /**********************************************************
  2561.  *      short sendname(struct Vars *v)
  2562.  *
  2563.  * Build file info block consisting of file name, length,
  2564.  * time, and mode
  2565.  **********************************************************/
  2566. short
  2567. sendname(struct Vars *v)
  2568. {
  2569.   struct SetupVars *sv;
  2570.   UBYTE    *p,
  2571.            *q,
  2572.             buff[32],
  2573.             mode[5];
  2574.   BPTR      FileLock;
  2575.  
  2576. /*
  2577.  * Initialize comm program transfer status display
  2578.  */
  2579.   v->Fsize = xpr_finfo(v->Filename, 1L);
  2580.   v->xpru.xpru_updatemask = XPRU_PROTOCOL | XPRU_FILESIZE | XPRU_MSG
  2581.     | XPRU_BLOCKS | XPRU_ERRORS | XPRU_TIMEOUTS | XPRU_BLOCKCHECK
  2582.     | XPRU_BYTES | XPRU_ELAPSEDTIME;
  2583.   v->xpru.xpru_protocol = "ZModem";
  2584.   v->xpru.xpru_filesize = v->Fsize;
  2585.   v->xpru.xpru_msg = (v->Lzconv == ZCNL) ? "MSG_SENDING_TEXT_FILE_TXT" :
  2586.     ((v->Lzconv == ZCBIN) ? "MSG_SENDING_BINARY_FILE_TXT" : "MSG_SENDING_FILE_TXT");
  2587.   v->xpru.xpru_blocks = v->xpru.xpru_errors = v->xpru.xpru_timeouts = 0;
  2588.   v->xpru.xpru_blockcheck = v->Crc32t ? "CRC-32" : "CRC-16";
  2589.   v->xpru.xpru_bytes = v->Strtpos = 0;
  2590.   v->xpru.xpru_blocksize = v->ksize;
  2591.   update_rate(v);
  2592.   display_update(&v->xpru);
  2593.  
  2594.   sv = (void *) v->io.xpr_data;
  2595.   if (*sv->option_s == 'Y')
  2596.     {
  2597.  /*
  2598.   * If "SY" option selected, send full path
  2599.   */
  2600.       strcpy(v->Pktbuf, v->Filename);
  2601.       p = v->Pktbuf + strlen(v->Pktbuf) + 1;
  2602.     }
  2603.   else
  2604.     {
  2605.  /*
  2606.   * else extract outgoing file name without directory path
  2607.   */
  2608.       for (p = v->Filename, q = v->Pktbuf; *p; ++p, ++q)
  2609.         if ((*q = *p) == '/' || *q == ':')
  2610.           q = v->Pktbuf - 1;
  2611.       *q = '\0';
  2612.       p = ++q;
  2613.     }
  2614.  
  2615. /*
  2616.  * Zero out remainder of file info packet
  2617.  */
  2618.   memset(p, 0, sizeof(v->Pktbuf) - (p - v->Pktbuf));
  2619.  
  2620. /*
  2621.  * Store file size, timestamp, and mode in info packet
  2622.  */
  2623.   if (v->FileAttributes & 1)
  2624.     {
  2625.       ULONG     Seconds = getsystime(NULL),
  2626.                 Mode = 0000;      /*
  2627.  
  2628.                                    * owner = rwx, group = rwx, others = rwx
  2629.                                    */
  2630.  
  2631.  /*
  2632.   * See if we can lock it, this probably won't work for `term'.
  2633.   */
  2634.       if (FileLock = Lock(v->Filename, ACCESS_READ))
  2635.         {
  2636.           struct FileInfoBlock __aligned FileInfo;
  2637.  
  2638.      /*
  2639.       * Any info available?
  2640.       */
  2641.           if (Examine(FileLock, &FileInfo))
  2642.             {
  2643.          /*
  2644.           * Modification date.
  2645.           */
  2646.               Seconds = (  FileInfo.fib_Date.ds_Days * 24 * 60
  2647.                         +  FileInfo.fib_Date.ds_Minute) * 60
  2648.                         + (FileInfo.fib_Date.ds_Tick) / TICKS_PER_SECOND;
  2649.  
  2650.          /*
  2651.           * Take care of the owner bits.
  2652.           */
  2653.               if (FileInfo.fib_Protection & FIBF_EXECUTE)
  2654.                 Mode |= 0100;
  2655.  
  2656.               if (FileInfo.fib_Protection & (FIBF_WRITE | FIBF_DELETE))
  2657.                 Mode |= 0200;
  2658.  
  2659.               if (FileInfo.fib_Protection & FIBF_READ)
  2660.                 Mode |= 0400;
  2661.  
  2662.          /*
  2663.           * Take care of the group bits.
  2664.           */
  2665.               if (!(FileInfo.fib_Protection & FIBF_GRP_EXECUTE))
  2666.                 Mode |= 0010;
  2667.  
  2668.               if (!(FileInfo.fib_Protection & FIBF_GRP_WRITE) || !(FileInfo.fib_Protection & FIBF_GRP_DELETE))
  2669.                 Mode |= 0020;
  2670.  
  2671.               if (!(FileInfo.fib_Protection & FIBF_GRP_READ))
  2672.                 Mode |= 0040;
  2673.  
  2674.          /*
  2675.           * Take care of the other bits.
  2676.           */
  2677.               if (!(FileInfo.fib_Protection & FIBF_OTR_EXECUTE))
  2678.                 Mode |= 0001;
  2679.  
  2680.               if (!(FileInfo.fib_Protection & FIBF_OTR_WRITE) || !(FileInfo.fib_Protection & FIBF_OTR_DELETE))
  2681.                 Mode |= 0002;
  2682.  
  2683.               if (!(FileInfo.fib_Protection & FIBF_OTR_READ))
  2684.                 Mode |= 0004;
  2685.             }
  2686.  
  2687.           UnLock(FileLock);
  2688.         }
  2689.  
  2690.       to_octal(buff, Seconds);
  2691.       to_octal(mode, Mode);
  2692.     }
  2693.   else
  2694.     {
  2695.       to_octal(buff, getsystime(NULL));
  2696.       to_octal(mode, 0000);
  2697.     }
  2698.  
  2699. /*
  2700.  * amiga.lib mysprintf() can't do %lo format, so we do it the hard way
  2701.  */
  2702. /*
  2703.  * Yes, octal; ZModem was originally done on Unix, and they like octal there
  2704.  */
  2705.  
  2706.   sprintf(p, "%ld %s %s", (v->Fsize < 0) ? 0L : v->Fsize, buff, mode);
  2707.  
  2708. /*
  2709.  * Send filename packet
  2710.  */
  2711.   return zsendfile(v, (short) (p - v->Pktbuf + strlen(p) + 1));
  2712. }       /*
  2713.          * End of short sendname()
  2714.          */
  2715.  
  2716. /**********************************************************
  2717.  *      short zsendfile(struct Vars *v, short blen)
  2718.  *
  2719.  * Send the filename packet and see if receiver will accept
  2720.  * file
  2721.  **********************************************************/
  2722. short
  2723. zsendfile(struct Vars *v, short blen)
  2724. {
  2725.   short     c;
  2726.  
  2727.   while (TRUE)
  2728.     {
  2729.       v->Txhdr[ZF0] = v->Lzconv;        /*
  2730.                                          * Text or Binary mode; from config
  2731.                                          * string
  2732.                                          */
  2733.       v->Txhdr[ZF1] = LZMANAG;  /*
  2734.                                  * Default file management mode
  2735.                                  */
  2736.       v->Txhdr[ZF2] = LZTRANS;  /*
  2737.                                  * Default file transport mode
  2738.                                  */
  2739.       v->Txhdr[ZF3] = 0;
  2740.       zsbhdr(v, ZFILE);
  2741.       zsdata(v, blen, ZCRCW);
  2742.       sendbuf(v);
  2743.     again:
  2744.  /*
  2745.   * Check for abort from comm program
  2746.   */
  2747.       if ( xpr_chkabort() )
  2748.         {
  2749.           bfclose(v);
  2750.           canit(v);     /*
  2751.                          * Receiver does not respond to ZABORT.
  2752.                          */
  2753.           return ZM_ERROR;
  2754.         };
  2755.       switch (c = zgethdr(v))
  2756.         {
  2757.           case ZRINIT:
  2758.             goto again;
  2759.           case ZCAN:
  2760.           case ZCRC:
  2761.           case RCDO:
  2762.           case TIMEOUT:
  2763.           case ZABORT:
  2764.           case ZFIN:
  2765.             upderr(v, v->Msgbuf);
  2766.             return ZM_ERROR;
  2767.           case ZSKIP:   /*
  2768.                          * Receiver doesn't want this one
  2769.                          */
  2770.             upderr(v, "MSG_SKIP_COMMAND_RECEIVED_TXT");
  2771.             bfclose(v);
  2772.             return c;
  2773.           case ZRPOS:   /*
  2774.                          * Receiver wants it; this is starting position
  2775.                          */
  2776.             bfseek(v, v->Rxpos);
  2777.             v->Strtpos = v->Txpos = v->Rxpos;
  2778.             xpr_sflush();
  2779.             v->Modemcount = 0;
  2780.             return zsendfdata(v);
  2781.         }
  2782.     }
  2783. }       /*
  2784.          * End of short zsendfile()
  2785.          */
  2786.  
  2787. /**********************************************************
  2788.  *      short zsendfdata(struct Vars *v)
  2789.  *
  2790.  * Send the file data
  2791.  **********************************************************/
  2792. short
  2793. zsendfdata(struct Vars *v)
  2794. {
  2795.   short     c,
  2796.             e,
  2797.             blklen,
  2798.             goodbytes = 0;
  2799.   USHORT    framelen,
  2800.             maxblklen,
  2801.             goodneeded = 512;
  2802.  
  2803. /*
  2804.  * Figure out max data packet size to send
  2805.  */
  2806.   maxblklen = v->ksize;
  2807.   if (v->Rxbuflen && maxblklen > v->Rxbuflen)
  2808.     maxblklen = v->Rxbuflen;
  2809.   blklen = (v->Baud < 1200) ? 256 : v->ksize;
  2810.   if (blklen > maxblklen)
  2811.     blklen = maxblklen;
  2812.  
  2813. /*
  2814.  * If an interruption happened, handle it; else keep sending data
  2815.  */
  2816. somemore:
  2817.   while (char_avail(v))
  2818.     {
  2819.  /*
  2820.   * Check for another incoming packet while discarding line noise
  2821.   */
  2822.       switch (readock(v, 1))
  2823.         {
  2824.           case ZM_CAN:
  2825.           case RCDO:
  2826.           case ZPAD:
  2827.             break;
  2828.           default:
  2829.             continue;
  2830.         }
  2831.     waitack:
  2832.       switch (c = getinsync(v))
  2833.         {
  2834.           default:
  2835.             upderr(v, "MSG_TRANSFER_CANCELED_TXT");
  2836.             bfclose(v);
  2837.             return ZM_ERROR;
  2838.           case ZSKIP:   /*
  2839.                          * Receiver changed its mind and wants to skip the
  2840.                          * file
  2841.                          */
  2842.             bfclose(v);
  2843.             return c;
  2844.           case ZACK:    /*
  2845.                          * ACK at end of frame; resume sending data
  2846.                          */
  2847.             break;
  2848.           case ZRPOS:   /*
  2849.                          * An error; resend data from last good point
  2850.                          */
  2851.             blklen >>= 2;
  2852.             if (blklen < MINBLOCK)
  2853.               blklen = MINBLOCK;
  2854.             if (goodneeded < MAXGOODNEEDED)
  2855.               goodneeded <<= 1;
  2856.             v->xpru.xpru_updatemask = XPRU_ERRORS;
  2857.             ++v->xpru.xpru_errors;
  2858.             display_update (&v->xpru);
  2859.             break;
  2860.           case ZRINIT:
  2861.             updmsg(v, "MSG_DONE_TXT");
  2862.             return OK;
  2863.         }
  2864.     }
  2865.  
  2866. /*
  2867.  * Transmit ZDATA frame header
  2868.  */
  2869.   framelen = v->Rxbuflen;
  2870.   stohdr(v, v->Txpos);
  2871.   zsbhdr(v, ZDATA);
  2872.  
  2873. /*
  2874.  * Keep sending data packets until finished or interrupted
  2875.  */
  2876.   do
  2877.     {
  2878.  /*
  2879.   * Read next chunk of file data
  2880.   */
  2881.       c = bfread(v, v->Pktbuf, (long) blklen);
  2882.  
  2883.  /*
  2884.   * Figure out how to handle this data packet
  2885.   */
  2886.       if (c < blklen)
  2887.         e = ZCRCE;      /*
  2888.                          * If end of file, this is last data packet
  2889.                          */
  2890.       else if (v->Rxbuflen && (framelen -= c) <= 0)
  2891.         e = ZCRCW;      /*
  2892.                          * If end of frame, ask for ACK
  2893.                          */
  2894.       else
  2895.         e = ZCRCG;      /*
  2896.                          * Else tell receiver to expect more data packets
  2897.                          */
  2898.  
  2899.       zsdata(v, c, e);  /*
  2900.                          * Send the packet
  2901.                          */
  2902.       sendbuf(v);
  2903.  
  2904.  /*
  2905.   * Update comm program status display
  2906.   */
  2907.       v->xpru.xpru_updatemask = XPRU_BLOCKS | XPRU_BLOCKSIZE | XPRU_BYTES
  2908.         | XPRU_ELAPSEDTIME | XPRU_BLOCKCHECK;
  2909.       ++v->xpru.xpru_blocks;
  2910.       v->xpru.xpru_blocksize = c;
  2911.       v->xpru.xpru_blockcheck = v->Crc32t ? "CRC-32" : "CRC-16";
  2912.       v->xpru.xpru_bytes = v->Txpos += c;
  2913.       update_rate(v);
  2914.       display_update(&v->xpru);
  2915.  
  2916.  /*
  2917.   * If we've been sending smaller than normal packets, see if it's * time to
  2918.   * bump the packet size up a notch yet
  2919.   */
  2920.       if (blklen < maxblklen && (goodbytes += c) >= goodneeded)
  2921.         {
  2922.           blklen <<= 1;
  2923.           if (blklen > maxblklen)
  2924.             blklen = maxblklen;
  2925.           goodbytes = 0;
  2926.         }
  2927.  /*
  2928.   * Check for abort from comm program
  2929.   */
  2930.           if( xpr_chkabort() )
  2931.             {
  2932.               canit(v);         /*
  2933.                                  * Receiver does not respond to ZABORT.
  2934.                                  */
  2935.               upderr(v, "MSG_TRANSFER_CANCELED_TXT");
  2936.               bfclose(v);
  2937.               return ZM_ERROR;
  2938.             }
  2939.  /*
  2940.   * If this was last packet in frame, go wait for ACK from receiver
  2941.   */
  2942.       if (e == ZCRCW)
  2943.         goto waitack;
  2944.  
  2945.  /*
  2946.   * * Check if receiver trying to interrupt us; look for incoming packet *
  2947.   * while discarding line noise
  2948.   */
  2949.       while (char_avail(v))
  2950.         {
  2951.           switch (readock(v, 1))
  2952.             {
  2953.               case ZM_CAN:
  2954.               case RCDO:
  2955.               case ZPAD:
  2956.            /*
  2957.             * Interruption detected; stop sending and process complaint
  2958.             */
  2959.                 zsdata(v, 0, ZCRCE);
  2960.                 sendbuf(v);
  2961.                 goto waitack;
  2962.             }
  2963.         }
  2964.     }
  2965.   while (e == ZCRCG);   /*
  2966.                          * If no interruption, keep sending data packets
  2967.                          */
  2968.  
  2969. /*
  2970.  * Done sending file data; send EOF and wait for receiver to acknowledge
  2971.  */
  2972.   while (TRUE)
  2973.     {
  2974.       updmsg(v, "MSG_SENDING_EOF_TXT");
  2975.       stohdr(v, v->Txpos);
  2976.       zsbhdr(v, ZEOF);
  2977.       sendbuf(v);
  2978.       switch (c = getinsync(v))
  2979.         {
  2980.           case ZACK:
  2981.             continue;
  2982.           case ZRPOS:
  2983.             goto somemore;
  2984.           case ZRINIT:
  2985.             updmsg(v, "MSG_EOF_ACKNOWLEDGED_TXT");
  2986.             update_rate(v);
  2987.             v->xpru.xpru_updatemask = XPRU_ELAPSEDTIME;
  2988.             display_update(&v->xpru);
  2989.             return OK;
  2990.           case ZSKIP:
  2991.             bfclose(v);
  2992.             return c;
  2993.           default:
  2994.             upderr(v, "MSG_TRANSFER_CANCELED_TXT");
  2995.             bfclose(v);
  2996.             return ZM_ERROR;
  2997.         }
  2998.     }
  2999. }       /*
  3000.          * End of short zsendfdata()
  3001.          */
  3002.  
  3003. /**********************************************************
  3004.  *      short getinsync(struct Vars *v)
  3005.  *
  3006.  * Respond to receiver's complaint, get back in sync with
  3007.  * receiver
  3008.  **********************************************************/
  3009. short
  3010. getinsync(struct Vars *v)
  3011. {
  3012.   short     c;
  3013.  
  3014.   while (TRUE)
  3015.     {
  3016.       c = zgethdr(v);
  3017.       xpr_sflush();
  3018.       v->Modemcount = 0;
  3019.       switch (c)
  3020.         {
  3021.           case ZCAN:
  3022.           case ZABORT:
  3023.           case ZFIN:
  3024.           case RCDO:
  3025.           case TIMEOUT:
  3026.             upderr(v, v->Msgbuf);
  3027.             return ZM_ERROR;
  3028.           case ZRPOS:
  3029.             bfseek(v, v->Rxpos);
  3030.             v->Txpos = v->Rxpos;
  3031.             sprintf(v->Msgbuf, "MSG_RESENDING_FROM %ld", v->Txpos);
  3032.             upderr(v, v->Msgbuf);
  3033.             return c;
  3034.           case ZSKIP:
  3035.             upderr(v, "MSG_SKIP_COMMAND_RECEIVED");
  3036.        /*
  3037.         * fallthrough...
  3038.         */
  3039.           case ZRINIT:
  3040.             bfclose(v);
  3041.        /*
  3042.         * fallthrough...
  3043.         */
  3044.           case ZACK:
  3045.             return c;
  3046.           default:
  3047.             zsbhdr(v, ZNAK);
  3048.             sendbuf(v);
  3049.             continue;
  3050.         }
  3051.     }
  3052. }       /*
  3053.          * End of short getinsync()
  3054.          */
  3055.  
  3056. /**********************************************************
  3057.  *      void saybibi(struct Vars *v)
  3058.  *
  3059.  * End of batch transmission; disengage cleanly from receiver
  3060.  **********************************************************/
  3061. void
  3062. saybibi(struct Vars *v)
  3063. {
  3064.   while (TRUE)
  3065.     {
  3066.       stohdr(v, 0L);
  3067.       zsbhdr(v, ZFIN);
  3068.       sendbuf(v);
  3069.       switch (zgethdr(v))
  3070.         {
  3071.           case ZFIN:
  3072.             sendline(v, 'O');
  3073.             sendline(v, 'O');
  3074.             sendbuf(v);
  3075.        /*
  3076.         * fallthrough...
  3077.         */
  3078.           case ZCAN:
  3079.           case RCDO:
  3080.           case TIMEOUT:
  3081.             return;
  3082.         }
  3083.     }
  3084. }       /*
  3085.          * End of void saybibi()
  3086.          */
  3087. /**********************************************************************
  3088.  * Utils.c: Miscellaneous support routines for xprzmodem.library;
  3089.  * Version 2.10, 12 February 1991, by Rick Huebner.
  3090.  * Released to the Public Domain; do as you like with this code.
  3091.  *
  3092.  * Version 2.50, 15 November 1991, by William M. Perkins.  Added code
  3093.  * to update_rate() function in utils.c to avoid the Guru # 80000005
  3094.  * you would have gotten if you had decided to adjust the system clock
  3095.  * back during an upload or download.
  3096.  *
  3097.  * Mysprintf() function to replace sprintf() and proto code to use
  3098.  * libinit.o and linent.o library code was supplied by Jim Cooper of SAS.
  3099.  *
  3100.  * Version 2.54, 28 June 1993, by Olaf `Olsen' Barthel. Got rid of the
  3101.  * timer.c code, added OS 2.0 dependencies, rewrote update_rate() to
  3102.  * display only the information which was really available, added
  3103.  * control-code escaping & run-length encoding, changed the abort
  3104.  * routine to pay attention to the different abort levels, removed
  3105.  * SAS/C library dependencies (octal conversion, etc.), added
  3106.  * support for proper file creation date and access permission bits.
  3107.  **********************************************************************/
  3108.  
  3109. /*
  3110.  * Transfer options to use if XProtocolSetup not called
  3111.  */
  3112. struct SetupVars Default_Config =
  3113. {
  3114.   NULL, NULL, 0,
  3115.   {"C"},
  3116.   {"N"},
  3117.   {"16"},
  3118.   {"0"},
  3119.   {"10"},
  3120.   {"N"},
  3121.   {"N"},
  3122.   {"N"},
  3123.   {"Y"},
  3124.   {"N"},
  3125.   {"Y"},
  3126.   {""},
  3127.   {"1024"},
  3128.   {"S"}
  3129. };
  3130.  
  3131. /*
  3132.  * Convert a string to all upper case characters.
  3133.  */
  3134. VOID
  3135. string_upper(STRPTR buf)
  3136. {
  3137.   UBYTE     c;
  3138.  
  3139.   while (c = *buf)
  3140.     *buf++ = ToUpper(c);
  3141. }
  3142.  
  3143. /*
  3144.  * Skip blanks in a string.
  3145.  */
  3146. STRPTR
  3147. skip_blank(STRPTR buf)
  3148. {
  3149.   UBYTE     c;
  3150.  
  3151.   while (c = *buf)
  3152.     {
  3153.       if (c == ' ' || c == ',' || c == '\t' || c == '\r' || c == '\n')
  3154.         buf++;
  3155.       else
  3156.         break;
  3157.     }
  3158.  
  3159.   return (buf);
  3160. }
  3161.  
  3162.  
  3163. /*
  3164.  * Get the local time, convert it to GMT.
  3165.  */
  3166. ULONG
  3167. getsystime(struct timeval *tv)
  3168. {
  3169.   struct timeval Now;
  3170.  
  3171.   GetSysTime(&Now);
  3172.   if (tv)
  3173.     {
  3174.       tv->tv_secs = Now.tv_secs;
  3175.       tv->tv_micro = 0;
  3176.     }
  3177.  
  3178.   return (Now.tv_secs);
  3179. }
  3180.  
  3181. /**********************************************************
  3182.  *      long XProtocolCleanup(struct XPR_IO *xio)
  3183.  *
  3184.  * Called by comm program to give us a chance to clean
  3185.  * up before program ends
  3186.  **********************************************************/
  3187. long
  3188. XProtocolCleanup(struct XPR_IO *xio)
  3189. {
  3190. /*
  3191.  * Release option memory, if any
  3192.  */
  3193.   if (xio->xpr_data)
  3194.     {
  3195.       FreeMem(xio->xpr_data, (long) sizeof(struct SetupVars));
  3196.  
  3197.       xio->xpr_data = NULL;
  3198.     }
  3199.  
  3200.   return XPRS_SUCCESS;
  3201. }       /*
  3202.          * End of long XProtocolCleanup()
  3203.          */
  3204. /**********************************************************
  3205.  *      struct Vars *setup(struct XPR_IO *io)
  3206.  *
  3207.  * Perform setup and initializations common to both Send
  3208.  * and Receive routines
  3209.  **********************************************************/
  3210. struct Vars *
  3211. setup(struct XPR_IO *io)
  3212. {
  3213.   extern long BaudTable[];
  3214.   struct SetupVars *sv;
  3215.   struct Vars *v;
  3216.   long      origbuf;
  3217. /*
  3218.  * Hook in default transfer options if XProtocolSetup wasn't called
  3219.  */
  3220.   if (!(sv = (void *) io->xpr_data))
  3221.     {
  3222.       io->xpr_data = AllocMem((long) sizeof(struct SetupVars), MEMF_PUBLIC | MEMF_CLEAR);
  3223.       if (!(sv = (void *) io->xpr_data))
  3224.         {
  3225.           ioerr(io, "MSG_NOT_ENOUGH_MEMORY_TXT");
  3226.           return NULL;
  3227.         }
  3228.       *sv = Default_Config;
  3229.     }
  3230.  
  3231. /*
  3232.  * Allocate memory for our unshared variables, to provide reentrancy
  3233.  */
  3234.   if (!(v = AllocMem((long) sizeof(struct Vars), MEMF_PUBLIC | MEMF_CLEAR)))
  3235.     {
  3236.     nomem:
  3237.       ioerr(io, "MSG_NOT_ENOUGH_MEMORY_TXT");
  3238.       return NULL;
  3239.     }
  3240.   v->Modemchar = v->Modembuf;
  3241.  
  3242. /*
  3243.  * * Allocate memory for our file I/O buffer; if we can't get as much as *
  3244.  * requested, keep asking for less until we hit minimum before giving up
  3245.  */
  3246.   v->Filebufmax = origbuf = atol(sv->option_b) * 1024;
  3247.   while (!(v->Filebuf = AllocMem(v->Filebufmax, 0L)))
  3248.     {
  3249.       if (v->Filebufmax > 1024)
  3250.         v->Filebufmax -= 1024;
  3251.       else
  3252.         {
  3253.           FreeMem(v, (long) sizeof(struct Vars));
  3254.  
  3255.           goto nomem;
  3256.         }
  3257.     }
  3258.  
  3259. /*
  3260.  * If framelength was intended to match buffer size, stay in sync
  3261.  */
  3262.   v->Tframlen = atol(sv->option_f);
  3263.   if (v->Tframlen && v->Tframlen == origbuf)
  3264.     v->Tframlen = v->Filebufmax;
  3265.  
  3266.   v->ErrorLimit = atol(sv->option_e);
  3267.  
  3268. /*
  3269.  * If selected, enable control character escape mode.
  3270.  */
  3271.   if (sv->option_c[0] == 'Y')
  3272.     v->Zctlesc = 1;
  3273.   else
  3274.     v->Zctlesc = 0;
  3275.  
  3276. /*
  3277.  * Take care of the file attribute options.
  3278.  */
  3279.   if (sv->option_i[0] == 'S')
  3280.     v->FileAttributes = 1;
  3281.   else
  3282.     {
  3283.       if (sv->option_i[0] == 'R')
  3284.         v->FileAttributes = 2;
  3285.       else
  3286.         v->FileAttributes = 3;
  3287.     }
  3288.  
  3289. /*
  3290.  * Get the maximum allowed packet size.
  3291.  */
  3292.   if ((v->ksize = atol(sv->option_m)) < MINBLOCK)
  3293.     v->ksize = MINBLOCK;
  3294.   else
  3295.     {
  3296.       if (v->ksize > KSIZE)
  3297.         v->ksize = KSIZE;
  3298.     }
  3299.  
  3300. /*
  3301.  * Copy caller's io struct into our Vars for easier passing
  3302.  */
  3303.   v->io   = *io;
  3304.   v->Baud = BaudTable[cfg.sysBaud];  /* set the current baud rate */
  3305.  
  3306.   return v;
  3307. }       /*
  3308.          * End of struct Vars *setup()
  3309.          */
  3310.  
  3311. /**********************************************************
  3312.  *      void set_textmode(struct Vars *v)
  3313.  *
  3314.  * Set text/binary mode flags in accordance with T option
  3315.  * setting
  3316.  **********************************************************/
  3317. void
  3318. set_textmode(struct Vars *v)
  3319. {
  3320.   struct SetupVars *sv;
  3321.   long      i;
  3322.  
  3323.   sv = (void *) v->io.xpr_data;
  3324.   switch (*sv->option_t)
  3325.     {
  3326.       case 'Y': /*
  3327.                          * Force text mode on receive; suggest text mode on
  3328.                          * send
  3329.                          */
  3330.       TY:
  3331.         v->Rxascii = TRUE;
  3332.         v->Rxbinary = FALSE;
  3333.         v->Lzconv = ZCNL;
  3334.         break;
  3335.       case 'N': /*
  3336.                          * Force binary mode on receive; suggest binary mode
  3337.                          * on send
  3338.                          */
  3339.       TN:
  3340.         v->Rxascii = FALSE;
  3341.         v->Rxbinary = TRUE;
  3342.         v->Lzconv = ZCBIN;
  3343.         break;
  3344.       case 'C': /*
  3345.                          * Ask comm program for proper mode for this file
  3346.                          */
  3347.             i = xpr_finfo(v->Filename, 2L);
  3348.             if (i == 1)         /*
  3349.                                  * Comm program says use binary mode
  3350.                                  */
  3351.               goto TN;
  3352.             if (i == 2)         /*
  3353.                                  * Comm program says use text mode
  3354.                                  */
  3355.               goto TY;
  3356.    /*
  3357.     * xpr_finfo() not provided (or failed); default to T?
  3358.     */
  3359.       case '?':
  3360.         v->Rxascii = v->Rxbinary = FALSE;
  3361.         v->Lzconv = 0;
  3362.         break;
  3363.     }
  3364. }       /*
  3365.          * End of void set_textmode()
  3366.          */
  3367.  
  3368. /**********************************************************
  3369.  *      UBYTE *find_option(UBYTE *buf, UBYTE option)
  3370.  *
  3371.  * Search for specified option setting in string
  3372.  **********************************************************/
  3373. UBYTE    *
  3374. find_option(UBYTE *buf, UBYTE option)
  3375. {
  3376.   while (*buf)
  3377.     {
  3378.       buf = skip_blank(buf);
  3379.  
  3380.       if (*buf == option)
  3381.         return ++buf;
  3382.  
  3383.       buf = skip_chars(buf);
  3384.     }
  3385.  
  3386.   return NULL;
  3387. }       /*
  3388.          * End of UBYTE *find_option()
  3389.          */
  3390.  
  3391. /**********************************************************
  3392.  *      void canit(struct Vars *v)
  3393.  *
  3394.  * send cancel string to get the other end to shut up
  3395.  **********************************************************/
  3396. void
  3397. canit(struct Vars *v)
  3398. {
  3399.   static char canistr[] =
  3400.   {24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
  3401.    8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0};
  3402.  
  3403.   zmputs(v, canistr);
  3404. }       /*
  3405.          * End of void canit()
  3406.          */
  3407.  
  3408. /**********************************************************
  3409.  *      void zmputs(struct Vars *v, UBYTE *s)
  3410.  *
  3411.  * Send a string to the modem, with processing for \336 (sleep 1 sec)
  3412.  * and \335 (break signal, ignored since XPR spec doesn't support it)
  3413.  **********************************************************/
  3414. void
  3415. zmputs(struct Vars *v, UBYTE *s)
  3416. {
  3417.   UBYTE     c;
  3418.  
  3419.   while (*s)
  3420.     {
  3421.       switch (c = *s++)
  3422.         {
  3423.           case '\336':
  3424.             Delay(TICKS_PER_SECOND);
  3425.           case '\335':
  3426.             break;
  3427.           default:
  3428.             sendline(v, c);
  3429.         }
  3430.     }
  3431.   sendbuf(v);
  3432. }       /*
  3433.          * End of void zmputs()
  3434.          */
  3435.  
  3436. /**********************************************************
  3437.  *      void xsendline(struct Vars *v, UBYTE c)
  3438.  *
  3439.  * Write one character to the modem
  3440.  **********************************************************/
  3441. void
  3442. xsendline(struct Vars *v, UBYTE c)
  3443. {
  3444.   v->Outbuf[v->Outbuflen++] = c;
  3445.   if (v->Outbuflen >= sizeof(v->Outbuf))
  3446.     sendbuf(v);
  3447. }       /*
  3448.          * End of void xsendline()
  3449.          */
  3450.  
  3451. /**********************************************************
  3452.  *      void sendbuf(struct Vars *v)
  3453.  *
  3454.  * Send any data waiting in modem output buffer
  3455.  **********************************************************/
  3456. void
  3457. sendbuf(struct Vars *v)
  3458. {
  3459.   if (v->Outbuflen)
  3460.     {
  3461.  /*
  3462.   * Do the bookkeeping.
  3463.   */
  3464.       v->BytesSent += v->Outbuflen;
  3465.       xpr_swrite(v->Outbuf, (long) v->Outbuflen);
  3466.       v->Outbuflen = 0;
  3467.     }
  3468. }       /*
  3469.          * End of void sendbuf()
  3470.          */
  3471.  
  3472. /**********************************************************
  3473.  *      short readock(struct Vars *v, short tenths)
  3474.  *
  3475.  * Get a byte from the modem;
  3476.  * return TIMEOUT if no read within timeout tenths of a
  3477.  * second, return RCDO if carrier lost or other fatal error
  3478.  * (sread returns -1).  Added in some buffering so we
  3479.  * wouldn't hammer the system with single-byte serial port
  3480.  * reads.  Also, the buffering makes char_avail() a lot
  3481.  * easier to implement.
  3482.  **********************************************************/
  3483. short
  3484. readock(struct Vars *v, short tenths)
  3485. {
  3486.   long      t;
  3487.  
  3488. /*
  3489.  * If there's data waiting in our buffer, return next byte
  3490.  */
  3491.   if (v->Modemcount)
  3492.     {
  3493.     gotdata:
  3494.       --v->Modemcount;
  3495.       return (short) (*v->Modemchar++);
  3496.     }
  3497. /*
  3498.  * Our buffer is empty; see if there's anything waiting in system buffer. *
  3499.  * If the caller is in a hurry, don't wait around, but if it can spare * a
  3500.  * half second, wait a bit and build up some input so we don't do as * many
  3501.  * sread() calls.
  3502.  */
  3503.   t = (tenths < 5) ? 0 : 500000;
  3504.   v->Modemcount = xpr_sread(v->Modembuf, (long) sizeof(v->Modembuf),
  3505.                                       t);
  3506.   if (v->Modemcount < 0)        /*
  3507.                                  * Carrier dropped or other fatal error;
  3508.                                  * abort
  3509.                                  */
  3510.     {
  3511.       v->Modemcount = 0;
  3512.       return RCDO;
  3513.     }
  3514.   else if (!v->Modemcount)      /*
  3515.                                  * Nothing in system buffer; try waiting
  3516.                                  */
  3517.     {
  3518.       t = tenths * 100000L - t;
  3519.       v->Modemcount = xpr_sread(v->Modembuf, 1L, t);
  3520.       if (v->Modemcount < 0)
  3521.         {
  3522.           v->Modemcount = 0;
  3523.           return RCDO;
  3524.         }
  3525.       else if (!v->Modemcount)  /*
  3526.                                  * Nothing received in time
  3527.                                  */
  3528.         return TIMEOUT;
  3529.     }
  3530.  
  3531. /*
  3532.  * Do the bookkeeping.
  3533.  */
  3534.   v->BytesReceived += v->Modemcount;
  3535.  
  3536. /*
  3537.  * Reset buffer pointer to start of data
  3538.  */
  3539.   v->Modemchar = v->Modembuf;
  3540.   goto gotdata;
  3541. }       /*
  3542.          * End of short readock()
  3543.          */
  3544.  
  3545. /**********************************************************
  3546.  *      char char_avail(struct Vars *v)
  3547.  *
  3548.  * Check if there's anything available to read from the
  3549.  * modem
  3550.  **********************************************************/
  3551. char
  3552. char_avail(struct Vars *v)
  3553. {
  3554.   if (v->Modemcount)
  3555.     return TRUE;
  3556.  
  3557. /*
  3558.  * No data in our buffer; check system's input buffer
  3559.  */
  3560.   v->Modemcount = xpr_sread(v->Modembuf, (long) sizeof(v->Modembuf), 0L);
  3561.   if (v->Modemcount < 1)        /*
  3562.                                  * Nothing in system buffer either
  3563.                                  */
  3564.     {
  3565.       v->Modemcount = 0;
  3566.       return FALSE;
  3567.     }
  3568.   else
  3569.     {
  3570.  /*
  3571.   * Do the bookkeeping.
  3572.   */
  3573.       v->BytesReceived += v->Modemcount;
  3574.  
  3575.  /*
  3576.   * System buffer had something waiting for us
  3577.   */
  3578.       v->Modemchar = v->Modembuf;
  3579.       return TRUE;
  3580.     }
  3581. }       /*
  3582.          * End of char char_avail()
  3583.          */
  3584.  
  3585. /**********************************************************
  3586.  *      void update_rate(struct Vars *v)
  3587.  *
  3588.  * Update the elapsed time, expected total time, and
  3589.  * effective data transfer rate values for status display
  3590.  **********************************************************/
  3591. void
  3592. update_rate(struct Vars *v)
  3593. {
  3594.   ULONG     elapsed,
  3595.             expect,
  3596.             throughput,
  3597.             time,
  3598.             oldrate = v->xpru.xpru_datarate;
  3599.   struct timeval Now;
  3600.  
  3601. /*
  3602.  * What time is it?
  3603.  */
  3604.   GetSysTime(&Now);
  3605.  
  3606. /*
  3607.  * Now calculate the time elapsed since the protocol started * transferring
  3608.  * the current file.
  3609.  */
  3610.   if (CmpTime(&Now, &v->Starttime) > 0)
  3611.     Now.tv_secs = Now.tv_micro = 0;
  3612.   else
  3613.     SubTime(&Now, &v->Starttime);
  3614.   elapsed = Now.tv_secs;
  3615.  
  3616. /*
  3617.  * Now take a look at the data that go through so far.
  3618.  */
  3619.   if (v->Receiving)
  3620.     throughput = v->BytesReceived;
  3621.   else
  3622.     throughput = v->BytesSent;
  3623.  
  3624. /*
  3625.  * Cut off the lowest 24 bits.
  3626.  */
  3627.   if (throughput > 0x00FFFFFF)
  3628.     throughput = 0xFFFFFF00;
  3629.   else
  3630.     throughput = throughput << 8;
  3631.  
  3632. /*
  3633.  * Now calculate the time.
  3634.  */
  3635.   if (elapsed > 0x00FFFFFF)
  3636.     time = 0xFFFFFF00 | (Now.tv_micro >> 12);
  3637.   else
  3638.     time = (elapsed << 8) | (Now.tv_micro >> 12);
  3639.  
  3640. /*
  3641.  * Finally, calculate the effective number of characters * transferred per
  3642.  * second.
  3643.  */
  3644.   if (time)
  3645.     {
  3646.       if (v->xpru.xpru_datarate = throughput / time)
  3647.         v->xpru.xpru_updatemask |= XPRU_DATARATE;
  3648.       else
  3649.         v->xpru.xpru_updatemask &= ~XPRU_DATARATE;
  3650.     }
  3651.   else
  3652.     {
  3653.       v->xpru.xpru_datarate = 0;
  3654.       v->xpru.xpru_updatemask &= ~XPRU_DATARATE;
  3655.     }
  3656.  
  3657. /*
  3658.  * Any changes?
  3659.  */
  3660.   if (v->xpru.xpru_datarate == oldrate)
  3661.     v->xpru.xpru_updatemask &= ~(XPRU_DATARATE | XPRU_EXPECTTIME);
  3662.  
  3663. /*
  3664.  * Compute expected total transfer time based on data rate so far
  3665.  */
  3666.   if (v->xpru.xpru_filesize <= 0 || !v->xpru.xpru_datarate)
  3667.     v->xpru.xpru_updatemask &= ~XPRU_EXPECTTIME;
  3668.   else
  3669.     {
  3670.       if ((expect = (v->xpru.xpru_filesize - v->Strtpos) / v->xpru.xpru_datarate) < elapsed)
  3671.         expect = elapsed;
  3672.  
  3673.       v->xpru.xpru_updatemask |= XPRU_EXPECTTIME;
  3674.     }
  3675.  
  3676. /*
  3677.  * Any data to display?
  3678.  */
  3679.   if (v->xpru.xpru_updatemask & XPRU_EXPECTTIME)
  3680.     {
  3681.       v->xpru.xpru_expecttime = (char *) v->Msgbuf;
  3682.  
  3683.       sprintf(v->xpru.xpru_expecttime, "%02ld:%02ld:%02ld", expect / (60 * 60), (expect / 60) % 60, expect % 60);
  3684.  
  3685.       v->xpru.xpru_elapsedtime = &v->xpru.xpru_expecttime[strlen(v->xpru.xpru_expecttime) + 1];
  3686.     }
  3687.   else
  3688.     v->xpru.xpru_elapsedtime = v->Msgbuf;
  3689.  
  3690.   sprintf(v->xpru.xpru_elapsedtime, "%02ld:%02ld:%02ld", elapsed / (60 * 60), (elapsed / 60) % 60, elapsed % 60);
  3691. }
  3692.  
  3693. /**********************************************************
  3694.  *      long bfopen(struct Vars *v, UBYTE *mode)
  3695.  *
  3696.  * Buffered file I/O fopen() interface routine
  3697.  **********************************************************/
  3698. FILE *
  3699. bfopen(struct Vars *v, UBYTE *mode)
  3700. {
  3701. /*
  3702.  * Initialize file-handling variables
  3703.  */
  3704.   v->Filebufpos = v->Filebuflen = v->Filebufcnt = 0;
  3705.   v->Fileflush = FALSE;
  3706.   v->Filebufptr = v->Filebuf;
  3707. /*
  3708.  * Open the file
  3709.  */
  3710.   return fopen (v->Filename, mode);
  3711. }
  3712.  
  3713. /**********************************************************
  3714.  *      void bfclose(struct Vars *v)
  3715.  *
  3716.  * Buffered file I/O fclose() interface routine
  3717.  **********************************************************/
  3718. void
  3719. bfclose(struct Vars *v)
  3720. {
  3721.   if (v->File)
  3722.     {
  3723.  /*
  3724.   * If bfwrite() left data in buffer, flush it out before closing
  3725.   */
  3726.       if (v->Fileflush)
  3727.         fwrite (v->Filebuf, 1L, v->Filebufcnt, v->File);
  3728.  
  3729.  /*
  3730.   * Close the file
  3731.   */
  3732.       fclose (v->File);
  3733.  
  3734.  /*
  3735.   * Let's see if we should muck with the file attributes.
  3736.   */
  3737.       if (v->SetAttributes && (v->FileAttributes & 2))
  3738.         {
  3739.           ULONG     Bits = 0,
  3740.                     Seconds;
  3741.  
  3742.             Seconds = 0;
  3743.  
  3744.      /*
  3745.       * Take care of the owner bits.
  3746.       */
  3747.           if (v->Bits & 0100)
  3748.             Bits |= FIBF_EXECUTE;
  3749.  
  3750.           if (v->Bits & 0200)
  3751.             Bits |= FIBF_WRITE | FIBF_DELETE;
  3752.  
  3753.           if (v->Bits & 0400)
  3754.             Bits |= FIBF_READ;
  3755.  
  3756.      /*
  3757.       * Now for the group bits.
  3758.       */
  3759.           if (!(v->Bits & 0010))
  3760.             Bits |= FIBF_GRP_EXECUTE;
  3761.  
  3762.           if (!(v->Bits & 0020))
  3763.             Bits |= FIBF_GRP_WRITE | FIBF_GRP_DELETE;
  3764.  
  3765.           if (!(v->Bits & 0040))
  3766.             Bits |= FIBF_GRP_READ;
  3767.  
  3768.      /*
  3769.       * Now for the other bits.
  3770.       */
  3771.           if (!(v->Bits & 0001))
  3772.             Bits |= FIBF_OTR_EXECUTE;
  3773.  
  3774.           if (!(v->Bits & 0002))
  3775.             Bits |= FIBF_OTR_WRITE | FIBF_OTR_DELETE;
  3776.  
  3777.           if (!(v->Bits & 0004))
  3778.             Bits |= FIBF_OTR_READ;
  3779.  
  3780.      /*
  3781.       * Try to change the attributes.
  3782.       */
  3783.           SetProtection(v->Filename, Bits);
  3784.  
  3785.      /*
  3786.       * Now for the modification date.
  3787.       */
  3788.           if (Seconds)
  3789.             {
  3790.               struct DateStamp __aligned Date;
  3791.  
  3792.               Date.ds_Days = Seconds / 86400;
  3793.               Date.ds_Minute = (Seconds % 86400) / 60;
  3794.               Date.ds_Tick = (Seconds % 60) * TICKS_PER_SECOND;
  3795.  
  3796.               SetFileDate(v->Filename, &Date);
  3797.             }
  3798.         }
  3799.  
  3800.       v->File = NULL;
  3801.     }
  3802. }       /*
  3803.          * End of void bfclose()
  3804.          */
  3805.  
  3806. /**********************************************************
  3807.  *      void bfseek(struct Vars *v, long pos)
  3808.  *
  3809.  * Buffered file I/O fseek() interface routine
  3810.  **********************************************************/
  3811. void
  3812. bfseek(struct Vars *v, long pos)
  3813. {
  3814.   long      offset;
  3815.  
  3816. /*
  3817.  * If new file position is within currently buffered section, reset pointers
  3818.  */
  3819.   if (pos >= v->Filebufpos && pos < v->Filebufpos + v->Filebuflen)
  3820.     {
  3821.       offset = pos - v->Filebufpos;
  3822.       v->Filebufptr = v->Filebuf + offset;
  3823.       v->Filebufcnt = v->Filebuflen - offset;
  3824.  /*
  3825.   * Otherwise, fseek() file & discard buffer contents to force new read
  3826.   */
  3827.     }
  3828.   else
  3829.     {
  3830.       fseek (v->File, pos, SEEK_SET);
  3831.       v->Filebuflen = v->Filebufcnt = 0;
  3832.       v->Filebufpos = pos;
  3833.     }
  3834. }       /*
  3835.          * End of void bfseek()
  3836.          */
  3837.  
  3838. /**********************************************************
  3839.  *      long bfread(struct Vars *v, UBYTE *buf, long length)
  3840.  *
  3841.  * Buffered file I/O fread() interface routine
  3842.  **********************************************************/
  3843. long
  3844. bfread(struct Vars *v, UBYTE *buf, long length)
  3845. {
  3846.   long      count,
  3847.             total = 0;
  3848.  
  3849. /*
  3850.  * Keep going until entire request completed
  3851.  */
  3852.   while (length > 0)
  3853.     {
  3854.  /*
  3855.   * Copy as much of the request as possible from the buffer
  3856.   */
  3857.       count = (length <= v->Filebufcnt) ? length : v->Filebufcnt;
  3858.       CopyMem(v->Filebufptr, buf, count);
  3859.       buf += count;
  3860.       total += count;
  3861.       length -= count;
  3862.       v->Filebufptr += count;
  3863.       v->Filebufcnt -= count;
  3864.  
  3865.  /*
  3866.   * If we've emptied the buffer, read next buffer's worth
  3867.   */
  3868.       if (!v->Filebufcnt)
  3869.         {
  3870.           v->Filebufpos += v->Filebuflen;
  3871.           v->Filebufptr = v->Filebuf;
  3872.           v->Filebufcnt = v->Filebuflen
  3873.             = fread (v->Filebuf, 1L, v->Filebufmax, v->File);
  3874.      /*
  3875.       * If we hit the EOF, return with however much we read so far
  3876.       */
  3877.           if (!v->Filebufcnt)
  3878.             break;
  3879.         }
  3880.     }
  3881.   return total;
  3882. }       /*
  3883.          * End of long bfread()
  3884.          */
  3885.  
  3886. /**********************************************************
  3887.  *      long bfwrite(struct Vars *v, UBYTE *buf, long length)
  3888.  *
  3889.  * Buffered file I/O fwrite() interface routine
  3890.  **********************************************************/
  3891. long
  3892. bfwrite(struct Vars *v, UBYTE *buf, long length)
  3893. {
  3894.   long      count,
  3895.             total = 0;
  3896.  
  3897. /*
  3898.  * Keep going until entire request completed
  3899.  */
  3900.   while (length > 0)
  3901.     {
  3902.  /*
  3903.   * Copy as much as will fit into the buffer
  3904.   */
  3905.       count = v->Filebufmax - v->Filebufcnt;
  3906.       if (length < count)
  3907.         count = length;
  3908.       CopyMem(buf, v->Filebufptr, count);
  3909.       buf += count;
  3910.       total += count;
  3911.       length -= count;
  3912.       v->Filebufptr += count;
  3913.       v->Filebufcnt += count;
  3914.       v->Fileflush = TRUE;
  3915.  
  3916.  /*
  3917.   * If we've filled the buffer, write it out
  3918.   */
  3919.       if (v->Filebufcnt == v->Filebufmax)
  3920.         {
  3921.           count = fwrite(v->Filebuf, 1L, v->Filebufcnt, v->File);
  3922.           if (count < v->Filebufcnt)
  3923.             return -1;
  3924.           v->Filebufptr = v->Filebuf;
  3925.           v->Filebufcnt = 0;
  3926.           v->Fileflush = FALSE;
  3927.         }
  3928.     }
  3929.   return total;
  3930. }       /*
  3931.          * End of long bfwrite()
  3932.          */
  3933.  
  3934. /**********************************************************
  3935.  *      void ioerr(struct XPR_IO *io, char *msg)
  3936.  *
  3937.  * Have the comm program display an error message for us,
  3938.  * using a temporary XPR_UPDATE structure; used to display
  3939.  * errors before Vars gets allocated
  3940.  **********************************************************/
  3941. void
  3942. ioerr(struct XPR_IO *io, char *msg)
  3943. {
  3944.   struct XPR_UPDATE xpru;
  3945.  
  3946.       xpru.xpru_updatemask = XPRU_ERRORMSG;
  3947.       xpru.xpru_errormsg = msg;
  3948.       display_update(&xpru);
  3949. }       /** End of void ioerr() */
  3950.  
  3951. /**********************************************************
  3952.  *      void upderr(struct Vars *v, char *msg)
  3953.  *
  3954.  * Have the comm program display an error message for us, using the
  3955.  * normal XPR_IO structure allocated in Vars
  3956.  **********************************************************/
  3957. void
  3958. upderr(struct Vars *v, char *msg)
  3959. {
  3960.   v->xpru.xpru_updatemask = XPRU_ERRORMSG;
  3961.   v->xpru.xpru_errormsg = (STRPTR) msg;
  3962.   if ((STRPTR) msg == v->Msgbuf)        /*
  3963.                                          * Ensure message length < 50
  3964.                                          */
  3965.     msg[48] = '\0';
  3966.   display_update (&v->xpru);
  3967. }
  3968.  
  3969. /**********************************************************
  3970.  *      void updmsg(struct Vars *v,char *msg)
  3971.  *
  3972.  * Have the comm program display a normal message for us
  3973.  **********************************************************/
  3974. void
  3975. updmsg(struct Vars *v, char *msg)
  3976. {
  3977.   v->xpru.xpru_updatemask = XPRU_MSG;
  3978.   v->xpru.xpru_msg = (STRPTR) msg;
  3979.   if ((STRPTR) msg == v->Msgbuf)        /*
  3980.                                          * Ensure message length < 50
  3981.                                          */
  3982.     msg[48] = '\0';
  3983.   display_update(&v->xpru);
  3984. }
  3985.  
  3986. /**********************************************************
  3987.  *      long getfree(void)
  3988.  *
  3989.  * Figure out how many bytes are free on the drive we're uploading to.
  3990.  * Stubbed out for now; not supported by XPR spec.
  3991.  **********************************************************/
  3992. long
  3993. getfree(struct Vars *v)
  3994. {
  3995.   LONG      Space = 0x7FFFFFFF;   /*
  3996.                                    * = Unknown
  3997.                                    */
  3998.   return (Space);
  3999.  
  4000. }
  4001.  
  4002. /**********************************************************
  4003.  *      char exist(struct Vars *v)
  4004.  *
  4005.  * Check whether file already exists; used to detect
  4006.  * potential overwrites
  4007.  **********************************************************/
  4008. char
  4009. exist(struct Vars *v)
  4010. {
  4011.   FILE *alock;
  4012.   alock = fopen(v->Filename,"R");
  4013.   if( alock )
  4014.     {
  4015.     fclose(alock);
  4016.     };
  4017.   return (char)(alock != NULL);
  4018. }
  4019.